13.1 new和delete
13.1.1 单个对象的建立与删除
这个过程中发生了什么:
1)为对象分配内存。
2)调用构造函数,并传递内存指针给构造函数,new操作要确保传递给构造函数的指针指向的内存是有效的。
对象a所占的空间被删除,且析构函数被调用,data指向的内存被释放
对象b所占的空间被释放,但是析构函数没有被调用,data指向的内存没有被释放,内存泄漏了。
要点:
1) delete删除的对象必须是使用new分配的,否则结果不可知。
2) delete一个空指针(为零),不会发生什么。建议delete一个指针后,将其设置为0。
3) new和delete的大部分行为也是通过malloc和free来实现。
4) delete void*指针,释放内存,但不会调用对象的析构函数。这可能导致内存泄露。
13.1.2 new[ ]和delete[ ]
如果构造函数X没有设置默认参数int m = 0,编译出错
分配和删除对象
通过一个例子来展示:单个对象和对象数组的分配和删除
1)使用new[]分配,必须用delete[]释放
2)使用new[]分配对象数组,此对象所属的类必须要有无参数构造函数或者带参数构造函数中所有参数提供了默认参数值
3)数组中构造函数和析构函数调用顺序:
MyType[0],MyType[1] …
对象调用析构函数:
MyType[5],MyType[4],MyType[3]
也就是析构函数调用顺序和构造函数调用顺序是相反的。
13.1.1 单个对象的建立与删除
MyType *fp = new MyType(1,2); //1,2是构造函数的参数
MyType *fg = new MyType; // 要有无参数的构造函数,或者是用户没有定义编译器提供
// 的无参数构造函数(所谓的默认构造函数default constructor)
MyType *fg = new MyType();
这个过程中发生了什么:
1)为对象分配内存。
2)调用构造函数,并传递内存指针给构造函数,new操作要确保传递给构造函数的指针指向的内存是有效的。
删除单个对象
MyType *fp = new MyType(1,2);
delete fp;
这个过程发生了:
1)调用析构造函数
2)释放对象所占内存
一个void *指针可能导致问题
#include <iostream>
using namespace std;
class Object {
void* data; // Some storage
const int size;
const char id;
public:
Object(int sz, char c) : size(sz), id(c) {
data = new char[size];
cout << "Constructing object " << id
<< ", size = " << size << endl;
}
~Object() {
cout << "Destructing object " << id << endl;
delete []data; // OK, just releases storage,
// no destructor calls are necessary
}
};
int main() {
Object* a = new Object(40, 'a');
delete a;
void* b = new Object(40, 'b');
delete b;
}
结果:
Constructing object a, size = 40
Destructing object a
Constructing object b, size = 40
对象a所占的空间被删除,且析构函数被调用,data指向的内存被释放
对象b所占的空间被释放,但是析构函数没有被调用,data指向的内存没有被释放,内存泄漏了。
要点:
1) delete删除的对象必须是使用new分配的,否则结果不可知。
2) delete一个空指针(为零),不会发生什么。建议delete一个指针后,将其设置为0。
3) new和delete的大部分行为也是通过malloc和free来实现。
4) delete void*指针,释放内存,但不会调用对象的析构函数。这可能导致内存泄露。
13.1.2 new[ ]和delete[ ]
class X {
public:
X(int m = 0){ i = m;}
int i;
};
main()
{
X *p = new X[10];
}
如果构造函数X没有设置默认参数int m = 0,编译出错
分配和删除对象
通过一个例子来展示:单个对象和对象数组的分配和删除
MyType *fp = new MyType[100];
MyType *fp2 = new MyType;
delete fp2;
delete []fp; // 老版本的C++中delete [100]fp;
要点:
1)使用new[]分配,必须用delete[]释放
2)使用new[]分配对象数组,此对象所属的类必须要有无参数构造函数或者带参数构造函数中所有参数提供了默认参数值
3)数组中构造函数和析构函数调用顺序:
MyType[0],MyType[1] …
对象调用析构函数:
MyType[5],MyType[4],MyType[3]
也就是析构函数调用顺序和构造函数调用顺序是相反的。
11.1.3 内存耗尽的处理
使用new分配内存,如果内存耗尽,则默认情况下new_handler会被调用,此函数会抛出一个异常。开发者可以使用自己的处理函数,方法是:
#include <new>
set_new_handler(your_funciton)
your_function要求没有参数和返回值。
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;
int count = 0;
void out_of_memory() {
cerr << "memory exhausted after " << count
<< " allocations!" << endl;
exit(1);
}
int main() {
set_new_handler(out_of_memory);
while(1) {
count++;
new int[1000]; // Exhausts memory
}
}
注意:如果定义了自己版本的new,则new_handler不会被调用,除非加入代码来实现。