delete 和 delete []

当调用delete的时候,系统会自动调用已分配的对象的析构函数。当我们用new [] 分配的对象是基本数据类型时,用delete和delete [] 没有区别。但是,当分配的对象是自定义对象时,二者不能通用。一般来说使用new分配的对象,用delete来释放。用new[] 分配的内存用delete [] 来逐个释放。

delete与delete[]需要注意的地方 

1:首先来说一个大家容易忽略的问题: 定义:int *p=new int; 

这个大家一看就知道,在内存中分配了一个int类型的空间,没错。但是我想说的是,操作系统在堆在分配了一个int类型空间给p指向的空间,但是p本身的值是在栈上,我觉的明白这个很重要。比如,你需要处理一个海量数据,这个数据需要用二维数组来表示,你如果这样定义int *ptr[MaxNum],然后再循环为每个ptr[0~MaxNum-1]分配空间,这个时候容易隐含一个错误,我们知道内存中栈的大小大约就2M左右,而堆很大,几乎没有限制,当你的MaxNum很大的时候,就会导致内存溢出,因为ptr这个值的本身是在栈上的,而栈的大小就2M左右,而你又有这么多个地址要存放,所以会出错。解决办法有二个:一:用一维数据代替二维数组;二:定义一个二维指针; 然后再动态分配。 


2:delete与delete[]执行遇到的问题:
 ①   int  *p=new int[100];       int  num[100];       p=num;       delete []p; 

大家能看出这段代码有什么问题吗?如果你还没看出,那么你对指针及内存的动态分配与释放还需要再学习。 

错误是发生在delete []p,为什么呢?按理说用new[]申请,用delete[]释放,应该没有问题啊。但是错误发生的原因是因为delete[]p释放的是数组num[100]的空间,而我们申请的空间根本就没有释放,为什么会出现这种情况呢?因为此时的指针已指向了num数组的首地址,而num[100]的空间会由系统自动释放,而我们现在强行释放,所以会发生错误。


 ②int *p=new int[3];    *p=1; 

   p++;//p的指向改变了,指向了下一空间    *p=2;    delete []p; 

大家能发现这段代码有什么问题吗? 

错误还是发生在delete[]p,c/c++规定,当删除一个指针时,这个指针应指向其首地址,而上面的代码中p值已经发生了变化,所以会发生错误,如何避免呢?可以备份一份;如 int * pbak=p;在释放的时候,用delete[]pbak即可。 

③  int* p = new int[10];    int *pp=p;      delete []p;   delete []pp; 

这段代码哪里又发生了错误呢? 

我们要知道,p向操作系统申请了10个int类型的空间,而pp只是指向这个空间,操作系统并没有为其再分配10个int类型的空间,所以当你用delete[]p释放这个空间后,再用delete[]pp释放就会发生错误。其实不管用哪个释放,只要释放一次就行了。


 ④ int a=100;      itn *p=&a;      delete p; 

看到了这里,如果你还不能看出这段代码的错误,那你前面的白看了,说明你还是没有真正懂得啊! 错误还是发生在delete p,什么原因?因为p并没有通过new获得内存空间,只是指向某个变量,而delete p是强行释放a的空间,肯定发生错误啦。


我们通常从这样的认识:
delete 释放new分配的单个对象指针指向的内存
delete[] 释放new分配的对象数组指针指向的内存
那么,按照教科书的理解,我们看下下面的代码:
int *a = new int[10];
delete a;        //方式1
delete [] a;     //方式2
肯定会有很多人说方式1肯定存在内存泄漏,是这样吗?


3. 针对简单类型 使用new分配后的不管是数组还是非数组形式内存空间用两种方式均可 如:
   int *a = new int[10];
   delete a;
   delete [] a;
   此种情况中的释放效果相同,原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理,在析构时,系统并不会调用析构函数,
   它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间(在分配过程中 系统会记录分配内存的大小等信息,此信息保存在结构体_CrtMemBlockHeader中,
   具体情况可参看VC安装目录下CRT\SRC\DBGDEL.cpp)


4. 针对类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指针指向的全部内存空间


所以总结下就是,如果ptr代表一个用new申请的内存返回的内存空间地址,即所谓的指针,那么:
   delete   ptr   代表用来释放内存,且只用来释放ptr指向的内存。 
   delete[]   rg   用来释放rg指向的内存,!!还逐一调用数组中每个对象的destructor!! 
   对于像int/char/long/int*/struct等等简单数据类型,由于对象没有destructor,所以用delete 和delete [] 是一样的!但是如果是C++对象数组就不同了!

猜你喜欢

转载自blog.csdn.net/baidu_20351223/article/details/80208627