• 为什么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[]

  • 相关阅读:
    node path.resolve()和path.join()
    完美替代postman的接口测试工具—— apipost
    localforage indexedDB如何使用索引
    ApiPost V5 升级指南
    Chrome升级到91版本以上后Cookies SameSite问题,IdentityServer4登录不上问题?
    React直接调用Bootstrap的方案
    Golang的module模式下项目组织结构
    Linux部署SpringBoot项目jar包,输出日志到文件并追踪
    mybatis plus 查询语句
    springboot 引入AOP 切面 @Aspect 注解使用
  • 原文地址:https://www.cnblogs.com/fulina/p/6273931.html
Copyright © 2020-2023  润新知