我们都知道在c++中可以用new/malloc动态分配内存空间用delete/free释放动态开辟的内存空间。
c++中的malloc/free是继承c语言中的malloc/free,它的用法和在C语言中的用法一模一样。
1.那么既然c++中有了可以动态开辟内存的函数为什么又要有new/delete呢?
我们知道malloc只是单纯的开辟内存空间而不进行初始化,free只是将动态开辟的内存空间给释放了。
对于内置类型而言,用malloc/free开辟和释放内存没有一点问题,但是对于非内置类型来说,由于对象在创建的时候要调用构造函数进行初始化,而在对象在消亡的时候要调用析构函数进行一些清理工作,显然,malloc/free无法完成这些事情。
因此,c++中提供了new/delete两个操作符,用new在动态分配内存的时候调用构造函数进行初始化,delete在释放内存的时候自动调用析构函数进行清理。
2.new/delete的用法
A为非内置类型
class A { public: A(int a=0,int b=0) :_a(a) ,_b(b) { cout << "A()"<<endl; } ~A() { cout << "~A()" << endl; } private: int _a; };
注意:
new和delete,new[]和delete[]一定要成对出现,在下面我们会解释为什么new[]和delete[]要成对出现。
3.new和delete的内部实现:
通过跟踪调试程序,我们可以知道new和delete内部是通过调用一些函数实现的。
new内部是通过调用以下函数实现的
char * operatoer new(size_t count);
char * operator new[](size_t count);
delete内部是通过调用以下两个函数实现的:
void operator delete(char *p);
void operator delete(char *p);
具体调用顺序如下:
4.new和delete,new[]和delete[]为什么要成对出现?
1.malloc/free为防止内存泄漏,一定要成对出现。
2.new和delete成对出现的原因则是因为new开辟内存空间是调用构造函数创建对象,而如果不用delete释放空间而是用free,那么释放空间之前不会执行析构函数,有可能会导致内存泄漏。、
A *pa=new A;
free(pa);//错误
delete pa;//正确
3.new[]和delete[]为什么要成对出现呢?我们通过执行程序可以发现:
1.当我们用new[]开辟10个连续内置类型空间,而用delete释放,这时执行程序,程序不会崩溃。
int *p=new int[10];
delete p;
2.当我们用new[]开辟10个连续的非内置类型的空间,没有用delete[]释放,执行程序时,程序会崩溃。
A* pa=new A[10];
delete pa;
这是为什么呢?
当我们执行下面的程序,
我们发现执行
int *p=new int[10]开辟内存时传给operator new[](size_t count)的count是40;
A* pa=new A[10]开辟内存时传给operator new[](size_t count)的count是84;
这就说明了new在开辟内置类型的空间时,开辟得空间数量是指定的空间数量,字节数是指定的数量乘以类型的大小。
而在开辟非内置类型空间时,除了开辟指定数量的空间以外,还多开辟4个字节的空间。
new开辟非内置类型的空间时传给operator new[](size_t count)的count是类型的大小*空间的数量在加上4个字节,最前面的空间里放的是要执行析构函数的次数。它返回给a2的地址是最前面的空间的后一个空间的地址。
由于内置类型没有析构函数,因此没有多开辟空间。
非内置类型用delete[]在释放空间时调用operator delete[](char *p),而此时的p被编译器内部处理过后,它指向的是这些连续空间的最前面一个空间的地址,因此,而传给operator delete(char *p)的地址是处理过后的地址,因此,他可以释放一块连续的空间并且直到调用析构函数的次数。
而如果用delete,则直接调用operator delete(char *p),传给p的地址是a2的地址,如果释放它,就相当于释放动态开辟空间的一部分,这样会造成内存泄露,使程序崩溃,而编译器不知道调用多少次析构函数。