Destructors实质是释放资源;
类的析构执行顺序是先构造(Constructed)的(成员),最后被Destructors,数组成员同样如此,例如:数组a[0], a[1], ..., a[8], a[9]: 析构执行顺序是a[9], a[8], ..., a[1], a[0]:不能有参数,不能有返回值,不能重载;只能在(对象关闭)自动调用,不能显示调用析构函数(除非placement new),不可以调用两次。
值得注意的是不能显式调用析构函数,即使局部变量也不行。此时我们需要这样处理:
void someCode()
{
{
File f;
...........
}
// f 的析构函数在此处会被自动调用!
}
如果上述的方案还是不可行,我们可以考虑增加一个和析构函数等效的成员方法,例如:我们常见File类,就可增加一个Close()成员方法,但是要记住和析构函数一样,不能联系调用两次,我们可以将一个fileHandle_数据成员设置为 -1,并且在开头检查fileHandle_是否已经等于-1;
class File {
public:
void close();
~File();
...
private:
int fileHandle_; // fileHandle_ >= 0 if/only-if it's open
};
File::~File()
{
close();
}
void File::close()
{
if (fileHandle_ >= 0) {
...insert code to call the OS to close the file...
fileHandle_ = -1;
}
}
如果一个对象是new的,那么在delete中也不能显示调用析构函数,因为delete做了两件事,调用析构销毁对象和释放空间。这里的new可不是operator new,后者只是分配空间,并没调用构造函数。
placement最明显的作用就是把对象放到特定的内存位置。
#include <new> // Must #include this to use "placement new"
#include "Fred.h" // Declaration of class Fred
void someCode()
{
char memory[sizeof(Fred)]; // Line #1
void* place = memory; // Line #2
Fred* f = new(place) Fred(); // Line #3 (see "DANGER" below)
// The pointers f and place will be equal
...
}
Line #3中的构造函数中的this指针将等于place,f的返回值也是place,注意:placenew指向的指针要有足够的空间,并且需要为所创建的对象进行边界调整,编译器和系统不会对此进行任何检查,另外placenew的析构应该像如下这样编写:
void someCode()
{
char memory[sizeof(Fred)];
void* p = memory;
Fred* f = new(p) Fred();
...
f->~Fred(); // Explicitly call the destructor for the placed object
}
在编写析构函数时,也不能显正调用成员的析构函数,类的析构函数会自动调用成员的析构,按照和它们在类中的声明的顺序相反的顺序被析构。
在派生类的析构中,不能显式调用基类的析构。派生类的析构会自动调用基类的析构函数。在多重继承的情况下,直接基类以出现在继承列表中的顺序的反序被析构。