写在前面

今天来讲一些delete[]delete的相关知识,什么情况下我们应该使用delete[],什么情况下我们应该delete,以及错误使用会带来的问题。

正文

首先呢,我们需要构建一个简单的A类,然后对其做文章,详细看下面我的测试程序:

下面more命令显示的就是.cpp文件里面的内容,可以看到我还是利用静态的全局变量记录类的构造函数和析构函数的调用情况。然后我用new *p = new A[10]来在堆里面申请了10个A类对象大小的内存,之后啥也没干,啥delete也没用,直接结束了程序。

那么程序执行的结果是什么样子的呢?就是上面显示的结果了,可以看到,每个类的构造函数都得到了调用,但是却没有调用析构函数,按照道理来说,对象的生命周期结束之后,也应该会被系统自动回收内存呀,应该是下面这个结果:

测试程序:

细心的朋友应该已经发现了,对象生成的方式不一样,在第二种情况下,我没用new生成对象,而是直接按照类名+对象名的方式生成了对象,此时对象是存放在栈里的,所以在栈内程序结束之后析构函数会被自动调用。

堆里的对象不会自动被析构,所以说手动delete掉堆里面申请的内存是非常重要的。那么接下来看看如果正确回收new申请出来的对象数组内存,先看一下测试程序:

结果:

上述测试程序就是正确的释放对象数组内存的方式。

那么讲完正确的,我们来看看如果错误释放内存会发生什么呢?让我们来修改一下测试程序:

在这个测试程序里面,我给A类设计了一个set\_j()的函数,用来修改成员变量j的数值。我的目的是为了测试一下,对象在构造和析构时候的顺序关系。让我们来运行一下这段程序:

可以看到,在构造的时候我是按照j的数值从1到10来构造对象的,但是在析构的时候却是第10个对象先被析构,然后再是第9个,按照这个顺序进行析构,直到第1个对象被析构为止。示意图如下所示:

那么在这种情况下,用的是错误的delete而不是正确的delete[]的话会发生什么情况呢?我猜分配内存的指针可能是会指向数组里的最后一个对象,然后因为只是delete,所以编译器会尝试释放一块以指针p为首地址的,大小为10个对象内存大小的地址,但是因为没用delete[],所以程序可能会向后去释放内存,也就是非法的内存,然后程序会报错。

接下来让我们来试试这个事情:

可以看到,程序确实发生了崩溃,而且也是首先释放了第10个对象之后程序就崩溃了。但是,具体的崩溃原因并不能在这里体现出来。

因为异常我还没有做过测试,所以我就不再继续了,大家记住deletedelte[]正确使用的正确性,以及错误使用的后果就是我这篇文章的目的啦。

所以我们需要注意:当回收单个对象内存的时候,应该用delete,当回收对象数组的内存的时候,应该用delete[]

要想知道程序崩溃的真正原因,可以从以下2个方面下手:

1:阅读实现源码(强烈推荐);

2:利用异常机制进行测试;