C++的人,肯定知道 delete 要与 new 配对使用,delete[] 要与 new [] 配对使用。
平时也小心着使用,一般问题也不大。但是如果用错了会产生什么后果呢。
本文先介绍new,new[] ,delete ,delete [],然后再推导出后果。
一.new[]
1.调用operator new[] ,由operator new[]调用n次operator new 来分配n个对象的空间。
2.调用n次构造函数。
二.delete[]
1.调用n次析构函数。
2.调用operator delete[] ,由operator delete[]调operator delete来释放空间。
三.简单数据类型的new[] delete
void operator delete(void* p)
{
printf("释放内存\n");
free(p);
}int
int main()
{
int *p = new inr[10];
delete p;
}
输出结果: 释放内存
可以看到对于简单数据类型,使用new[] 和 delete 并没有问题(实则也没有造成内存泄漏)。
四.复杂数据类型的new[] delete
对于类内部没有自己定义析构函数的类型
#include<stdio.h>
#include<stdlib.h>
class A
{
public:
int a;
};
void operator delete(void* p)
{
printf("释放内存\n");
free(p);
}int main()
{
A* p = new A[10];
delete p;
}
运行结果: 释放内存
程序正常运行了,且空间正常释放。所以对于没有自己定义析构函数的数据类型也是可以的。
对于类内部自己定义析构函数的类型
#include<stdio.h>
#include<stdlib.h>
class A
{
public:
int a;
~A()
{}
};
void operator delete(void* p)
{
printf("释放内存\n");
free(p);
}
int main()
{
A* p = new A[10];
delete p;
}
这样的代码是不可以运行的,会抛出异常。那么为什么会这样?
上文说到的,delete[]做的两个工作,调用n次析构,调用operator delete 释放空间。
编译器在调用析构的工作上,做出了优化,有些数据类型的析构函数是系统合成的没有作用的析构函数(trivial destructor),对于这样的情况是没必要调用多次析构的,所以系统决定什么也不做,这样就只用释放空间就可以了。同样,简单数据类型也是这样的。
对于空间是否被完全释放的问题主要取决于类的内部是否有指针需要被释放,如果没有,就不存在内存泄漏的问题。
因为我们在分配内存的时候,其实会有两个cookie来存放这一次所申请内存的空间大小,所以无论是delete[] 还是 delete 都会完整的把申请的内存释放掉。但是如果,其中含有指针,我们一般会在析构函数中释放掉指针所指向的内存空间,可是使用delete只会调用一次析构,也就只会释放一次指针,其余指针所指向的内存就会泄漏。那么编译器要求,对于内部含有nontrivial destructor的类型,在释放时必须要每一个都得调用到它的析构函数,这样确保了每个对象内部的指针所指向的内存都会被释放。
本文探讨了C++中new[]和delete[]的正确配合,以及不正确使用可能导致的后果。重点讲解了类的析构函数在内存释放中的角色,以及为何需要区分简单和复杂数据类型。

693

被折叠的 条评论
为什么被折叠?



