定位new与对象
当使用定位new
运算符为对象分配内存时,注意调用对象的析构函数。因为delete
运算符必须跟new
配套使用,而不是跟定位new
配套使用。所以使用定位new
为对象分配空间并初始化对象之后,不能用delete
清除对象。这时如果对象的构造函数中使用new
申请了内存,就会导致内存泄漏,因为不能使用delete
清除对象。例如:
class BadString{
private:
int len;
char * str;
public:
BadString();
BadString(const char *);
~BadString();
void show();
};
BadString::BadString(){
str = new char[4];
len = 3;
strcpy(str, "C++");
cout << "Using default constructor for: " << str << endl;
}
BadString::BadString(const char * s){
len = strlen(s);
str = new char[len + 1];
strcpy(str, s);
cout << "Using self-defined constructor for: " << str << endl;
}
BadString::~BadString(){
cout << "Using destroyer for: " << str << endl;
delete [] str;
}
void BadString::show(){
cout<< "Printing current string: " << str << endl;
}
char * buffer = new char[512];
BadString * s1 = new (buffer) BadString("first");
s1->show();
//错误1,系统释放掉了整个buffer的空间
delete s1;
BadString * s2 = new (buffer + sizeof(BadString)) BadString("second");
//错误2,delete必须与new配套使用
BadString * s1 = new (buffer) BadString("first");
BadString * s2 = new (buffer + sizeof(BadString)) BadString("second");
delete s2;
//错误3,直接释放内存不会调用对象的析构函数
BadString * s1 = new (buffer) BadString("first");
BadString * s2 = new (buffer + sizeof(BadString)) BadString("second");
delete [] buffer;
//正确用法,手动调用析构函数
BadString * s1 = new (buffer) BadString("first");
BadString * s2 = new (buffer + sizeof(BadString)) BadString("second");
s1->~BadString();
s2->~BadString();
delete [] buffer;
在错误1中,不能将定位new
运算符与delete
配合使用。在这里虽然程序能够运行,并且也确实会调用s1
的析构函数。但是却会导致程序直接释放整个buffer
的空间,所以如果后面需要再次用到这个buffer
空间就会出错。
错误2与错误1一样,都是将定位new
运算符与delete
运算符配合使用。但是错误2甚至都不能正常运行,这是因为s1
跟buffer
指向的是同一个地址,所以系统让delete s1
这一语句运行。而s2
跟buffer
指向的不是同一个地址,所以系统判断该语句错误。
错误3中直接使用delete [] buffer
释放了这块内存,而不管在这块内存上面定义的两个对象。从而导致这两个对象的析构函数没有调用就直接被释放掉内存,从而导致内存泄漏。