`
zhangziyangup
  • 浏览: 1187087 次
文章分类
社区版块
存档分类
最新评论

new和delete必须成对出现吗?【网上集合贴+个人总结】

 
阅读更多

new和delete必须成对出现吗?【网上集合贴+个人总结】

1.从内存泄露与否的角度考虑

new delete不一定要成对出現。理论上是這樣的。但是从习惯上來說,new delete成對出現是一個好的習慣。爲什麽說不一定要成對出現呢?

这个问题在csdn上有一個牛人写过很长的文章,不知道有沒有人还能找到?我記得大概是這個意思。

1)认为一定要成对出現的,主要是因为动态分配内存之后,如果不释放,会造成内存泄露。

2)但是,实际上并不总是如此。从操作系统角度上說,内存不能释放,是因为原先指向該内存块的指针丟失了,(比如該指針指向了另一块内存)。这样的情況下,才会造成内存泄露。但是,如果使用了new分配了一块内存,但是指向該内存的指针一直在,一直指向該内存,那麽在程序结束的時候,系統会自动把該指針指向的内存释放掉,從操作系統角度上說,並沒有造成内存洩露。

所以,new delete客观的來説,並不一定需要成對出現。我们对内存泄露的真正含義理解的並不是很正确。

這是我看了那個牛人的文章后的体会,那篇文章中有不少例子和數据,還有编译結果解释。非常好,可惜我記不得題目了,沒找到,在這裡說說我的理解。

2.某选择题选项B、D

B,若P的类型由A强制转换为void*,那么执行语句delete P*时,类A的析构函数不会被调用

D,执行语句 A*P=new A[100]时,类A的构造函数只会被调用一次

class CBase

{

public:

       CBase() { cout <<"CBase is running!\n";}

       ~CBase() { cout <<"~CBase() is running!\n";}

};

 

int main()

{

       //选项B错误

       CBase * pBase = new CBase; //调用构造函数

       void * pVoid = (void *)pBase;

       delete pVoid; //肯定不會調用类A的析构函数

 

       //选项D错误

       CBase *pBaseN = newCBase[100]; //调用构造函数100次

       delete []pBaseN; //调用析构函数100次

 

       return 0;

}


3. C++内存分配之NEW DELETE

1newdelete 必须成对出现;——此处观点值得商榷

2new底层调用操作系统堆内存管理函数HeapAlloc来分配堆内存;

3delete操作符底层调用API接口函数HeapFree来释放堆内存;

数据的3种存储方式。

1。静态区:全局变量或者使用static约束的变量;

2。堆:程序执行时分配的内存;如new操作所分配的动态内存

3。栈:函数调用,局部变量。

以上3种方式的区别:注意,堆上分配的内存不会被操作系统自动回收。

以下为常见的动态内存调用和销毁:

语句一: int * pt

语句二: pt = new int;

语句三: delete pt

分步详解:

语句一:你声明了一个pt指针,四个字节,放在栈里面的(pt为局部变量,所属栈内存区域);

语句二:你new了一个int形的数据放在堆里面,再把这个数据的地址赋给pt。(动态分配内存,所属堆内存区域);

语句三:把pt指向的地址所占的内存释放掉。

1.释放的就是堆上面的那个int(动态销毁内存,所属堆内存区域数据销毁

2.pt还是存在的,还在栈里面。不过你查它的值时,变成了null。(pt为局部变量,所属栈内存区域,由操作系统自行销毁)。

如果能够明白以上内容,就可以避免编程过程中的许多问题和疑惑。

4. 实例角度分析

我记得当年学习C++基础的时候,老师曾经告诉我们:一般来说newdelete要成对出现,在使用完new申请的内存后要马上释放。我相信持这种说法的人不止我们老师一个人,养成良好的内存使用习惯固然重要,但如果因此就认为newdelete必须成对出现,使用完new得到的空间后就要马上用delete释放的话,就有点“大材小用”了,相信C++提供这一由用户控制的内存控制方法也不是只限于如此的使用方法。

正确灵活的,或许也是“高级”的使用方法,是在A处使用new申请一块内存,用一个指针指pA向它,之后在B处用指针pB指向pA所指向的空间,释放指针pA本身,接着释放pB所指向的内存空间,最后释放指针pB本身。

以下的代码是本过程的一个例子:

#include<iostream.h>
#include<string.h>
char* ReverseString(char* pSourceStr,int nLength)
{
	//这里在堆上动态申请了一个长度为nLength的内存空间pDescStr2
	char* pDescStr2=new char[nLength]; 

	for(int i=0;i<nLength;i++)
	{
		pDescStr2[nLength-i-1]=pSourceStr[i];
	}

	//结束前并没有释放pDescStr2所指向的内存空间
	return pDescStr2;
	//只是释放了pDescStr这个指针
}
void main()
{

	char pSourceStr[]={"abcdefghijk"};
	cout<<"The source string: \t"<<pSourceStr<<endl;

	//新建一个指向ReverseString()函数中申请到的内存的指针
	char* pDescStr=ReverseString(pSourceStr,strlen(pSourceStr));
	cout<<"The desc string: \t"<<pDescStr<<endl;

	//在这里释放ReverseString()函数中申请到的内存
	delete[] pDescStr;
	//清除pDescStr指针,以免在今后的使用中出现溢出
	pDescStr=NULL;
}


从上面的例子可以看出,newdelete并没有在同一个函数中出现,但是很明显这样做没有造成内存泄露(memory leak)

或许这样使用newdelete有点小儿科,达到ReverseString()函数的目的完全可以不必使用newdelete。我认为newdelete最大的用武之地是在线程通信和进程通信中:比如线程A要向线程B投递一条信息,并要求不等线程B做出反应线程A就要马上进行后面的操作,也就是要求使用PostMessage(...)函数来投递消息,而且发送的消息内容存储在一个50K或者更大的内存空间中,那就必须使用newdelete了,也就是在线程A中用new准备好这样一个庞大的消息,之后把指针发送给进程B,进程B在处理完消息之后用delete释放这块内存。

总而言之,newdelete并非我们想像的那么简单,除了我所提到的用处之外还有不少其他的用处,有待研究,希望与大家探讨。

分享到:
评论

相关推荐

    new delete二维数组

    在C++编程语言中,`new` 和 `delete` 是动态内存管理的关键操作。当我们处理二维数组时,这些操作显得尤为重要,因为它们涉及到在运行时动态分配和释放内存。二维数组在C++中通常用于表示表格或矩阵,其每个元素可以...

    浅析c++中new和delete的用法

    在C++编程语言中,`new` 和 `delete` 是两个重要的运算符,它们主要用于动态内存管理。本文将深入解析这两个运算符的用法,并提供实际应用中的示例。 首先,`new` 运算符的主要功能是为程序在运行时动态地分配内存...

    第六章答案对象的指针、this指针、const、new和delete.pdf

    8. **动态内存管理**:C++中的`new`和`delete`操作符用于动态分配和释放内存。`new`用于为对象分配内存,例如`ClassName* ptr = new ClassName();`,`delete`用于释放内存,如`delete ptr;`。忘记释放内存可能导致...

    LINQ to SQL语句(12)之Delete和使用Attach

    在LINQ to SQL中,我们可以直接操作对象模型,将数据库操作转化为对对象的操作,大大简化了数据库交互的复杂性。本篇将重点探讨两个关键概念:Delete操作和使用Attach方法。 首先,让我们深入理解LINQ to SQL中的...

    JAVA基础-集合

    `Map`接口用于存储键值对,其中键必须唯一。 #### List接口的实现类 - **ArrayList**:基于动态数组实现,查询效率高,线程不安全。 - **LinkedList**:基于双向链表实现,适合频繁的插入和删除操作,线程不安全。...

    Batch Delete File

    可以使用`System.IO.DirectoryInfo`类获取文件夹信息,并通过`GetFiles()`方法获取所有文件的`FileInfo`对象集合。 ```csharp var directory = new DirectoryInfo(Server.MapPath(@"~\path\to\folder")); FileInfo...

    C#对注册表的操作 c#注册表基类集合

    为了实现对注册表的高效管理和复用,可以创建一个注册表操作的基类集合,这个集合可以包含多个静态方法,分别对应不同的注册表操作。例如: - `AddKey(string keyPath)`: 添加新键。 - `RemoveKey(string keyPath...

    c&c++笔试题总结

    同时,内存管理(动态内存分配与释放,如malloc、calloc、free、new、delete等)是面试常考点,防止内存泄漏和野指针的出现是关键。 3. **结构体与联合体**:这两种数据结构允许我们自定义数据类型,理解它们的区别...

    解决SqlDataAdapter数据适配器update delete insert出错

    解决SqlDataAdapter数据适配器update delete insert出错 在.NET Framework中,SqlDataAdapter是ADO.NET...同时,本文也对相关的知识点进行了延伸,帮助读者更好地理解和掌握ADO.NET中的数据适配器和数据库连接的配置。

    运用集合实现——学生信息管理系统

    此外,为了提高代码的可维护性和复用性,可以考虑将上述功能封装为独立的方法,如`addStudent()`, `findStudent()`, `updateStudent()`, `deleteStudent()`, 和`printStudents()`。 总的来说,这个学生信息管理系统...

    c++特别版类的习题9 数组实现集合的交并差

    - 使用`new`动态分配内存,并在完成时使用`delete[]`释放内存。 #### 4. 成员函数细节 - **拷贝构造函数**: `intset(const intset& setobj)`用于创建新对象的拷贝。 - **赋值运算符**: `intset& operator=(const ...

    对二叉排序树的操作集合

    ### 对二叉排序树的操作集合 #### 一、概述 二叉排序树(Binary Search Tree,简称BST)是一种特殊的二叉树数据结构,其每个节点包含一个键值和两个指向其他节点的指针,分别称为左子树和右子树。在二叉排序树中,...

    MongoDB Java获取集合.pdf

    编译并运行该程序,你会看到控制台输出连接成功、认证成功以及集合创建和选择成功的消息。 在实际应用中,你可能会使用更复杂的逻辑,如执行查询、更新或删除操作。`DBCollection` 类提供了丰富的 API 来实现这些...

    CC++程序员应聘常见面试题集合

    3. **内存管理**:了解栈和堆的区别,以及动态内存分配(new, delete)的使用,是考察一个程序员基本功的重要方面。 4. **面向对象编程**:C++的OOP特性包括类、对象、封装、继承、多态。面试中,你可能需要解释...

    通过LitePal保存集合到本地(可增删改查)

    通过LitePal保存集合到本地(可增删改查) compile 'org.litepal.android:core:1.3.2' 第一步建立 Connector.getDatabase(); 保存: Book book = new Book(); book.setName("The Da Vinci Code"); book.set...

    LINQ体验——LINQ to SQL语句之Insert/Update/Delete操作

    "LINQ体验——LINQ to SQL语句之Insert/Update/Delete操作" 在本篇文章中,我们将继续讨论LINQ to SQL语句,重点介绍Insert/Update/Delete操作,这些操作在我们的程序中是最常用的。下面,我们将通过多个示例来详细...

    java集合详解

    对于对象集合,主要的操作包括添加(new)、删除(delete)和查找(find)。这些操作需要根据不同的应用场景选择合适的容器类型。例如: - **添加**:可以将新对象添加到集合的末尾、开头或其他特定位置。 - **删除**:从...

    Javascript 中类似Map集合的实现键值对

    在JavaScript中,`Map`集合是一个内置的数据结构,用于存储键值对,它与对象不同,因为对象的键必须是字符串或符号,而`Map`则可以使用任何可哈希的值作为键。这篇博客文章可能探讨了如何通过自定义方式实现一个类似...

    黑马面试的现场编程之总结

    今天,我们将对Java中的线程、IO流、File和集合进行总结和概述。 一、Java之Thread(线程) Java中的Thread(线程)是指在一个程序中可以并发执行的单元。线程可以通过继承Thread类或实现Runnable接口来创建。在...

    中兴c++面试题集合

    - **内存管理**:理解栈、堆、静态存储区的区别和作用,以及如何动态分配和释放内存(new/delete)。 - **对象与类**:掌握封装、继承和多态的基本概念,理解构造函数和析构函数的作用。 - **运算符重载**:了解...

Global site tag (gtag.js) - Google Analytics