所有代码均运行在visual studio2019、x64环境下

delete用于释放由new创建的单个对象,delete[]用于释放由new创建的数组对象,一般都是配对使用。

但是为什么delete不用于释放数组对象,delete[]为什么不用于释放单个对象,从两者的原理说起。

delete在使用时会经历两步:

  1. 调用指针所指向的对象的析构函数
  2. 调用free函数回收指针所指向的内存

delete[]也是两步:

  1. 调用指针所指向数组中每个对象的析构函数
  2. 调用free函数回收指针所指向的内存

两者在第一步都需要调用对象的析构函数,只是一次或是多次的区别,也因此对于数组对象,需要使用delete[],否则除了第一个数组中第一个对象析构函数被调用,之后的对象都不会调用析构函数,在对象持有指针或是一些系统资源如文件句柄,Socket等时,如果不在析构函数中进行释放,将造成内存泄漏。注意到了吗,上文中有个前提是需要调用析构函数,如果对象不显式存在析构函数,如基本数据类型int,char或是自定义数据类型中不显式定义析构函数,这时候delete和delete[]就没有区别,因为不需要调用析构函数。

class TestA
{
public:TestA() { }virtual ~TestA() { cout << "~A" << endl; }int i;
};class TestB
{
public:TestB() { }//virtual ~TestB() { cout << "~B" << endl; }int i;
};int main() {int* arr = new int[10];delete[] arr;int* arr2 = new int[10];delete arr2;TestB* b = new TestB[10];delete[] b;TestB* bb = new TestB[10];delete bb;TestA* a = new TestA[10];delete[] a;TestA* aa = new TestA[10];delete aa;        //在这里出错
}
~A
~A
~A
~A
~A
~A
~A
~A
~A
~A
~A

一共调用了11次析构函数,在最后一次程序报错。

但在这里还没有解决问题,为什么delete aa会报错呢,按理来说虽然只调用了一次析构函数,之后的对象都没有调用,但也无所谓啊,最多就是对象中的一些资源没有被释放,但分配的内存还是可以由free函数回收掉的。关于这一点我们先思考一个问题,对于delete[]而言,他是如何知道要调用多少个对象的析构函数的,当我们在new[]时,向操作系统申请一块内存,然后调用构造函数,申请的这块内存由操作系统进行管理,它记录内存首地址和长度,这样在调用free时传入首地址进行回收,试想一下,我们知道对象的大小,比如int四个字节,此时操作系统记录了分配内存的总长度,是不是就可以知道有多少个对象了,但可惜的是操作系统并没有提供访问 内存长度的接口,也因此无法知道内存长度。所有编译器在分配时,会在数组首地址之前再申请一块空间用于记录数组个数(如果没有析构函数就不需要知道个数,编译器也就不会多申请这块空间),对于x64,这个大小存储在数组首地址的前八个字节,对于x86则是前4个字节

class TestA
{
public:TestA() { }virtual ~TestA() { cout << "~A" << endl; }int i;
};int main() {int* arr = new int[10];cout << *((long long*)arr - 1) << endl;delete[] arr;TestA* a = new TestA[10];cout << *((long long*)a - 1) << endl;delete[] a;}
-144680349937434461
10
~A
~A
~A
~A
~A
~A
~A
~A
~A
~A

对于int数组,由于没有析构函数所有编译器就不会存储数组大小,所有取前8个字节内容是不确定的,而对于a则记录大小为10。此时我们解决一个问题,在分配含有析构函数的自定义对象时,会多申请8个字节用于记录数组大小,方便调用析构函数时知道要调用多少次,所以在使用delete去释放一个数组对象时,由于传入的是数组首地址,但是申请的内存应该是数组首地址再往前8个字节的位置,数组首地址操作系统并未记录,所以会出错,同样的,使用delete[]去释放单个对象,由于他会访问前8个字节取得大小从而决定调用多少次析构函数,这时候行为将会不确定,却决于前8个字节会是什么值,可能会调用很多次析构函数,但在最后free时会出错,因为new对象时记录的是首地址,而不是首地址-8。

可以使用该代码测试操作系统记录的地址

class TestA
{
public:TestA() { }~TestA() { cout << "~A" << endl; }int i;
};int main() {TestA* a = new TestA[10];free((long long*)a - 1);//free(a);  //会出错,因为会多分配8个字节,首地址不为a
}

delete和delete[]的理解相关推荐

  1. delete优化_深入理解JIT和编译优化

    点击上方的蓝字关注我吧 程序那些事 简介 小师妹已经学完JVM的简单部分了,接下来要进入的是JVM中比较晦涩难懂的概念,这些概念是那么的枯燥乏味,甚至还有点惹人讨厌,但是要想深入理解JVM,这些概念是 ...

  2. 深入理解C++ new/delete, new []/delete[]动态内存管理

    在C语言中,我们写程序时,总是会有动态开辟内存的需求,每到这个时候我们就会想到用malloc/free 去从堆里面动态申请出来一段内存给我们用.但对这一块申请出来的内存,往往还需要我们对它进行稍许的& ...

  3. C++ delete 和 delete []的区别

    转载自https://blog.csdn.net/cbNotes/article/details/38900799 1.我们通常从教科书上看到这样的说明: delete 释放new分配的单个对象指针指 ...

  4. delete 和 delete [] 的真正区别

    c++中对new申请的内存的释放方式有delete和delete[]两种方式,到底这两者有什么区别呢? 1.我们通常从教科书上看到这样的说明: delete 释放new分配的单个对象指针指向的内存 d ...

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

    为何new出的对象数组必须要用delete[]删除,而普通数组delete和delete[]都一样-------_CrtMemBlockHeader ------jiese1990 温馨提示: 该文所 ...

  6. delete 和 delete []

    当调用delete的时候,系统会自动调用已分配的对象的析构函数.当我们用new [] 分配的对象是基本数据类型时,用delete和delete [] 没有区别.但是,当分配的对象是自定义对象时,二者不 ...

  7. delete和delete[ ]、exit和return

    delete和delete[ ] 在C++中,申请堆上空间有着两种方式new和new[ ],new是用来申请单个元素空间,new[ ]是申请存放多个元素的连续空间. 空间申请方式的不同对应着空间释放的 ...

  8. delete 和 delete []的真正区别

    c++中对new申请的内存的释放方式有delete和delete[两种方式,到底这两者有什么区别呢? 1.我们通常从教科书上看到这样的说明: delete 释放new分配的单个对象指针指向的内存 de ...

  9. delete 和 delete[]真正区别

    我们通常从教科书上看到这样的说明: delete 释放new分配的单个对象指针指向的内存 delete[] 释放new分配的对象数组指针指向的内存 那么,按照教科书的理解,我们看下下面的代码: int ...

最新文章

  1. php求二维矩阵的最大子矩阵,最大子矩阵-动态规划
  2. 【函数】02、函数进阶
  3. 自用开源/免费软件收集
  4. cad中lisp文件给恶作剧_CAD中LISP程序使用方法
  5. Golang的演化历程
  6. centos 安装图形桌面
  7. jmeter录制脚本的步骤(很详细)
  8. python写界面c这算法_OpenCV算法精解:基于Python与C.pdf
  9. 高效记忆/形象记忆(05)110数字编码表 0-9
  10. 自动化运维工具puppet学习笔记之基础篇
  11. Java 编写一个类Letter,要求该类创建对象p,并调用方法printLetter输出英文字母表。
  12. Shell小技巧(一百零五)脚本中的空格小结
  13. php设置中国时区方法
  14. python程序设计中、文件有哪两种展现形态_智慧职教APPPython程序设计(常州工业职业技术学院)作业期末考试答案...
  15. finalcut剪切快捷键_final cut pro怎么用快捷键把时间线上的素材移动到入点或剪辑点...
  16. 【POI2013】bzoj3426 Tower Defence Game
  17. 软件测试的目的和意义
  18. 集合(List集合、数据结构、List集合的实现类)
  19. 为何有些文献查不到DOI?
  20. DB2利用db2advis进行查询优化

热门文章

  1. Win系统速览桌面功能失效 - 解决方案
  2. [Java GUI] 简易Java绘图程序实例
  3. 华为发布折叠屏官方适配方案
  4. 怎样更改图片格式?怎么转图片的格式?
  5. 转:告诉你一个真实的数字化
  6. Matlab img格式图片转为dicom格式
  7. 微信挂机托管服务器nodejs,怎么执行node app.js 脚本
  8. 2014华中首届手游创意大赛
  9. (转)TensorFlow--实现人脸识别实验精讲 (Face Recognition using Tensorflow)
  10. python少儿编程课件ppt_《Python 少儿趣味编程》