delete和delete[ ]的区别点
关于动态申请的内存,分两种情况:基本数据类型的分配和自定义数据类型的分配。两者不同。
1、基本数据类型
对于基本数据类型,假如有如下代码
int *a = new int[10];
...
delete a; // 方式1
delete [ ] a; //方式2
肯定会不少人认为方式1存在内存泄露,然而事实上是不会!针对简单的基本数据类型,方式1和方式2均可正常工作,因为:基本的数据类型对象没有析构函数,并且new 在分配内存时会记录分配的空间大小,则delete时能正确释放内存,无需调用析构函数释放其余指针。因此两种方式均可。
2、自定义数据类型
这里一般指类,假设通过new申请了一个对象数组,注意是对象数组,返回一个指针,对于此对象数组的内存释放,需要做两件事情:一是释放最初申请的那部分空间,二是调用析构函数完成清理工作。对于内存空间的清理,由于申请时记录了其大小,因此无论使用delete还是delete[ ]都能将这片空间完整释放,而问题就出在析构函数的调用上,当使用delete时,仅仅调用了对象数组中第一个对象的析构函数,而使用delete [ ]的话,将会逐个调用析构函数。
有如下代码:
#include <iostream>;
using namespace std;
class T {
public:
T() { cout << "constructor" << endl; }
~T() { cout << "destructor" << endl; }
};
int main()
{
const int NUM = 3;
T* p1 = new T[NUM];
cout << hex << p1 << endl; //输出P1的地址
// delete[] p1;
delete p1;
cout << endl;
T* p2 = new T[NUM];
cout << p2 << endl; //输出P2的地址
delete[] p2;
return 0;
}
大家可以自己运行这个程序,看一看 delete p1 和 delete[] p1 的不同结果,我就不在这里贴运行结果了。
从运行结果中我们可以看出,delete p1 在回收空间的过程中,只有 p1[0] 这个对象调用了析构函数,其它对象如 p1[1]、p1[2] 等都没有调用自身的析构函数,这就是问题的症结所在。如果用 delete[],则在回收空间之前所有对象都会首先调用自己的析构函数。
基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 都是应该可以的;但是对于类对象数组,只能用 delete[]。对于 new 的单个对象,只能用 delete 不能用 delete[] 回收空间。
所以一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用。
————————————————
delete 释放new分配的单个对象指针指向的内存
delete[] 释放new分配的对象数组指针指向的内存
那么,按照教科书的理解,我们看下下面的代码:
int *a = new int[10];
delete a; //方式1
delete [] a; //方式2
肯定会有很多人说方式1肯定存在内存泄漏,是这样吗?
下面给出总结性说明:
针对简单类型
使用new分配后的不管是数组还是非数组形式内存空间用两种方式均可
如:
int *a = new int[10];
delete a;
delete [] a;
此种情况中的释放效果相同,原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理,在析构时,系统并不会调用析构函数,它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间
(在分配过程中 系统会记录分配内存的大小等信息,此信息保存在结构体_CrtMemBlockHeader中具体情况可参看VC安装目录CRT\SRC\DBGDEL.cpp)
针对类Class
两种方式体现出具体差异,当你通过下列方式分配一个类对象数组:
class A
{
private:
char *m_cBuffer;
int m_nLen;
public:
A(){ m_cBuffer = new char[m_nLen]; }
~A() { delete [] m_cBuffer; }
};
A *a = new A[10];
delete a;
仅释放了a指针指向的全部内存空间 但是只调用了a[0]对象的析构函数 剩下的从a[1]到a[9]这9个用户自行分配的m_cBuffer对应内存空间将不能释放 从而造成内存泄漏
delete [] a;
调用使用类对象的析构函数释放用户自己分配内存空间并且 释放了a指针指向的全部内存空间
总结
对于像int/char/long/int*/struct等简单数据类型、由于其为基本数据类型没有析构函数,所以使用delete与delete []相同,两者都会释放申请的内存空间,不会有内存泄漏。
当new申请的是C++对象数组时,delete和delete[]差别就很大了,delete只会析构一个对象,而delete[]可以逐一调用数组中的析构函数。
delete ptr 代表用来释放内存,且只用来释放ptr指向的内存。
delete[] rg 用来释放rg指向的内存,还逐一调用数组中每个对象的destructor
建议
为了养成良好的编程习惯,new 和 delete 配套,new[] 和delete[]配套使用。