c++-关于delete和delete[ ]混用的未定义问题解释
(2)如果此时我们没写析构函数,他就会调用编译器生成的析构函数,不用记录次数(可能涉及更底层,我也不太清楚,望指正),也就不用多开一个整形。),那么调用几次就是个问题,这四个字节恰好是一个整形的大小,这个整形用以记录这块空间的对象个数,从而确定需要调用几次构造和析构函数。但是实际上,如果你自己写了析构函数那么总共分配了44个字节,如果没写析构函数那么才总共分配40个字节。不用调用析构函数也就不用计
·
我们知道delete用于释放一个动态空间,而delete[ ]用于释放多个动态空间,但是如果我们混用的话会导致什么问题?我在博客上看了许多文章,但不尽人意,因此写下这篇文章让你知其然知其所以然(浅薄的解释,望指正)。
先看一个案例吧
程序为:
class A
{
private:
int _a;
public:
A(int x = 0)
{
_a = x;
}
~A()
{
}
};
int main()
{
A* p = new A[10];
delete p;//混用delete
}
运行结果为:

但是如果我们不显式地写析构函数:
class A
{
private:
int _a;
public:
A(int x = 0)
{
_a = x;
}
/* ~A()
{
}*/
};
int main()
{
A* p = new A[10];
delete p;
}
结果是正常运行:

为什么会有上面的两种现象呢?
如果我问你在上面的例子中系统分配了多少空间给这10个A类对象,那你大概率会回答40字节。很好理解嘛,一个A是4个字节,10个就是40字节。
但是实际上,如果你给对象自己写了析构函数,那么总共分配了44个字节,如果没写析构函数那么才总共分配40个字节!
为什么写了析构函数就多了4个字节?
- 我们知道用delete[]释放这块空间后会自动调用析构函数,此时如果我们自己写了析构函数,delete[]就需要去调用它,那么谁告诉delete[]要调用几次析构函数,也就是我怎么知道这块空间里面有几个对象?实际上,多出来的这四个字节恰好是一个整形的大小,这个整形用以记录这块空间的对象个数,从而确定需要调用几次构造和析构函数。也就是说delete[]在释放一个对象的时候,先要获取对象个数,然后调用析构函数,而delete则不会获取对象个数,直接调用一次析构函数(因为delete默认就是为了处理单个对象)。
不过,我们要知道,p指针指向的仍然是第一个对象,只是在构造和析构时会向前走获取一下对象个数,具体关系如下:

为什么不写析构函数就不会多这4个字节?
- 如果此时我们没写析构函数,他就会调用编译器生成的析构函数,不用记录需要析构的次数,也就不用多开一个整形。
- 对于new出来的内置类型的数组空间,也不会记录需要析构的次数,混用不会报错,因为内置类型析构函数默认什么都不做,所以也没必要调用。
好,现在可以解释上面的例子了:
- delete默认从指针指向的位置释放空间,不去获取对象个数。而delete[ ]默认先前移获取对象个数,然后调用若干次析构函数,最后再释放内存。
- 如果多开了空间但仍然用delete释放空间的话指针不会先前移访问开头的4字节,不从内存起始地址进行释放操作就会出现段错误,但不写析构函数也就不会多开四字节空间,从而避免了这个错误
- 有趣的是,如果你使用delete[ ]释放单个对象,那么情况恰恰相反,只有写了析构函数才会报错,不论如何,记住上面的事实,就可以预测这种错误。
练习一下这个会报错吗?

不用调用析构函数也就不用计录对象个数,也就不多开空间,因此可以从指针指向位置释放空间,所以不会报错。
更多推荐
所有评论(0)