为什么new的普通数组用delete 和 delete[]都能正确释放

1. 源文章

2.对源文章的一些总结

 

1. 源文章

为何new出的对象数组必须要用delete[]删除,而普通数组delete和delete[]都一样-------_CrtMemBlockHeader

先看了这篇由同事推荐的文章,让我对new时申请内存时具体做的时候所了解。

对于delete,验证了对象数组 用 delete 删除不行(因为对象数组中还有一个元素大小4个字节,delete函数内操作的内存中会有4个字节的偏移,导致数据混乱),但没有回答普通数组为什么可以用delete 删除。

建议读者先看源文,再继续往下看。

 

2.对源文章的一些总结

1)new 有析构函数的对象数组 必须要用 delete[]删除

经过自己的试验,只有 new 有析构函数(不管是程序员显式定义的 还是由编译器创建的nontrival的析构函数(《深度探索C++对象模型》)) 的对象数组才会在内存中占用空间来记录对象个数。

普通数组和没有析构函数的对象数组都不会。

那为什么需要记录对象数组个数呢,就是为了要依次执行析构函数。几个对象就执行几次析构函数。因为析构函数时nontrival的。
而定义 delete [] 的原因,就是为了迎合 c++ 的 class 的析构函数的执行。

 

2)为什么普通数组释放 delete 和 delete[] 都一样 

没有找到delete[] 的具体实现 调试也进不去,猜测下:(以源文中最后的例子为例子)

delete 是默认调用一次析构函数,如果有需要调用的话;
delete[] 是根据 存的数组个数 来决定调用几次析构函数,当然如果没有存对象数组的个数,也就不需要调用析构函数了。

如果是delete p;
  不管p是什么 都把指针往前移动多少 8*4个字节,在清空内存之前 会先判断某个值是不是对的。---就像对象数组用了delete 就会出现某个值不对,就会出现断言错误
如果是delete[] p;
  判断p是不是有nontrival析构函数的对象数组,
    如果是的话就往前移动 9*4个字节,然后将前8*4个字节当作头,将 (数组元素个数+<yout data>)整个数据当成 pUserData,然后再进行析构函数的调用 和 一次性释放内存。
    如果不是的话,就调用delete p;----(猜测)这就是普通数组释放内存的情况。

 这些本质上都是在new的时候分配的内存结构有关。

 

3) 如果new[]不需要记录对象大小,而是用pHead中的nDataSize来推算会怎么样

在源文中有pHead中的nDataSize成员,记录了元素大小 ,从而可以推出元素个数:

元素对象个数 = pHead->nDataSize / sizeof(T) 

但是事实上,new / malloc 在分配内存的时候会 round up 到某个数的倍数(8 或 16 等,跟 malloc 具体实现有关)。也就是说nDataSize并不是等于 sizeof(T)*个数(会大于等于这个数)。根据这样来推算,就有可能多调用析构函数。

 

 

参考文章:

为什么 new[]/delete[] 需要记录对象个数? 

浅谈 C++ 中的 new/delete 和 new[]/delete[]

posted @ 2017-01-11 15:41  ivy_0709  阅读(1020)  评论(0编辑  收藏  举报