为什么new的普通数组用delete 和 delete[]都能正确释放
由同事推荐的一篇博客:
为何new出的对象数组必须要用delete[]删除,而普通数组delete和delete[]都一样-------_CrtMemBlockHeader
文章解释了delete 内部是怎么操作的,讲解也很生动形象。不过看了以后,我只知道了对象数组 用 delete 为什么不行,但是还是不知道普通数组为什么可以用delete[];
文章问的不正确,应该是 为何new出的有析构函数的对象数组必须要用delete[]删除。
经过试验,只有 new 有析构函数(不管是程序员显式定义的 还是由编译器创建的nontrival的析构函数(《深度探索C++对象模型》)) 的对象数组才会记录对象个数。普通数组和没有析构函数的对象数组都不会。
而这就是要记录对象数组个数的原因,就是为了要执行析构函数。就要要知道要执行几次析构函数。
是要定义 delete [] 的原因,就是为了迎合 c++ 的 class 的析构函数的执行。
为什么普通数组释放 delete 和 delete[] 都一样
没有找到delete[]的具体实现 调试也进不去 所以下面的都是我猜想的==,根据上面那篇文章
delete 是默认调用一次析构函数,如果有需要调用的话;
但是delete[] 是根据 存的数组个数 调用几次析构函数,当然如果没有存对象数组的个数,也就不需要调用析构函数了。
如果是delete p;
不管p是什么 都把指针往前移动多少 8*4个字节,在清空内存之前 会先判断某个值是不是对的。
如果是delete[] p;
是不是先检查p是不是有析构函数的对象数组,
如果是的话就往前移动 9*4个字节,然后将前8*4个字节当作头,将 (数组元素个数+<yout data>)整个数据当成 pUserData,然后再进行析构函数的调用 和 一次性释放内存。
如果不是的话,就调用delete p;
为什么 new[]/delete[] 需要记录对象个数?
作者:陈硕
链接:https://zhuanlan.zhihu.com/p/22455100
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
对于有 non-trivial destructor 的 class T, 现在通常的 C++ 实现会在 new[] 的时候多分配 sizeof(size_t) 字节用于保存数组大小,
在 delete[] 的时候会依次逆序调用数组中各对象的析构函数。有的文献管这多分配的几个字节叫 new cookie (Itanium C++ ABI)。
那或许有人会问,既然根据数组首地址就能知道分配了多少字节内存,那为什么 new[] 还需要再保存对象的数目?
这不是多余吗?直接用 内存长度 / sizeof(T) 不就可以算出需要析构多少个对象了?
原因很简单:
内存长度 / sizeof(T) >= 对象个数
因为 new / malloc 在分配内存的时候会 round up 到某个数的倍数(8 或 16 等,跟 malloc 具体实现有关),
即 内存长度 = round_up(sizeof(T) * 对象个数),那么反过来我们就不能用内存长度算出对象个数了,必须单独保存对象个数。
假如不采用 new cookie,如果 sizeof(Foo) == 4,那么 Foo* p = new Foo[28];
会分配 112 字节来构造 28 个对象,但实际会从 libc 拿到 116 字节,那么 delete[] p; 会析构 116/4 = 29 个对象,这就有大问题了。
因此,通常的 C++ 实现在必要时会在 new[] 的时候多分配 sizeof(size_t) 字节用于保存对象数目,而不是让 delete[] 依靠内存大小来算出需要析构多少个对象。
还看了一篇 可以参考下:
浅谈 C++ 中的 new/delete 和 new[]/delete[]
为什么new的普通数组用delete 和 delete[]都能正确释放的更多相关文章
- delete和delete[] 区别
// DeleteAndDelete[].cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <Windows.h> ...
- js中数组删除 splice和delete的区别,以及delete的使用
var test=[];test[1]={name:'1',age:1};test[2]={name:'2',age:2};test[4]={name:'3',age:3}; console.log( ...
- [skill] C++ delete VS delete []
delete 用来删除 new 返回的对象. 先调用对象的析构,然后释放指针指向的内存. delete[] 用来删除 new [] 返回的对象. 先调用数组中每一个对象的析构,然后释放指针指向的内存.
- 【转】 C++中delete和delete[]的区别
一直对C++中的delete和delete[]的区别不甚了解,今天遇到了,上网查了一下,得出了结论.做个备份,以免丢失. C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete ...
- C++:delete和delete[]释放内存的区别
C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]. 关于 new[] 和 delete[], ...
- C++中delete和delete[]的区别
C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]. 关于 new[] 和 delete[],其中又 ...
- 关于delete和delete[]
[精彩] 求问delete和delete[] 的区别??http://www.chinaunix.net/jh/23/311058.html C++告诉我们在回收用 new 分配的单个对象的内存空间的 ...
- C++中delete和delete[]的使用
偶然的机会要使用到动态分配整形数组,怎么删除new出来的东西一时有点模糊(也许一直就不知道),于是在VS上试了试(写代码时经常用这种方法去验证模凌两可的东西),总结出来有两点. 1.基本数据类型new ...
- C++中delete 和delete[]的区别
c++告诉我们在回收new分配的单个对象的内存空间的时候用delete, 回收new[ ]分配的一组对象的内存空间的时候用 delete[ ]; #include <iostream> ...
随机推荐
- smoke.js是一款基于HTML5 Canvas的逼真烟雾特效js插件。通过该js插件,可以非常轻松的在页面中制作出各种烟雾效果。
Smoke.js 是一个浏览器默认警告系统的JavaScript替代品,如果你想要跨浏览器与平台的标准化JavaScript警告窗口,Smoke.js就是你想要的. Smoke.js是一个轻量级且灵活 ...
- sublime text3 3103 激活码
—– BEGIN LICENSE —–Michael BarnesSingle User LicenseEA7E-8213858A353C41 872A0D5C DF9B2950 AFF6F667C4 ...
- (三)Harbor使用OpenLDAP认证登陆
接上一篇<安装Harbor>,安装好之后,接下来我们使用OpenLDAP来进行Harbor web界面的登陆验证及权限分配! OpenLDAP: 使用OpenLDAP的都知道,这是一个集 ...
- iOS 让UIButton根据文字内容自动计算宽高
Xcode自带的UIButton控件是没有办法根据文字内容计算自身的宽和高的,下面演示一下问题, 我用代码方式创建一个UIButton,并且设置了一些属性,下面看一下效果图 一切都是这么的美好,跟我们 ...
- js实现文本框或文本域在用户输入时(oninput)触发事件,操作元素
写在前面:给不同的文本框设定同样的效果,当文本框没有内容输入时,‘下一步’按钮不可用且透明度为0.5.当有内容输入时(并不是获得焦点时focus),‘下一步’按钮状态可用, 且透明度为1. <s ...
- [SQL基础教程] 4-2 数据删除(DELETE)
[SQL基础教程] C4 数据更新 4-2 数据删除(DELETE) DROP TABLE / DELETE DROP TABLE - 完全删除表 DELETE - 仅删除数据,保留表容器 DELET ...
- Linked List - leetcode
138. Copy List with Random Pointer //不从head走 前面加一个dummy node 从dummy走先连head 只需记录当前节点 //这样就不需要考虑是先new ...
- web.xml讲解
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "- ...
- spring framework - 整体架构
Spring Framework 3.2 采用分层架构设计,包含一些列的功能要素,总结为以下几个部分 Core Container 该模块是Spring的核心容器,包含有Beans.Core.Cont ...
- 低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端
低功耗蓝牙BLE外围模式(peripheral)-使用BLE作为服务端 Android对外模模式(peripheral)的支持 从Android5.0开始才支持 关键术语和概念 以下是关键BLE术语和 ...