在c ++中,我们喜欢在析构函数中做一些事情。但在什么样的情况下,析构函数不会被调用?
以下情况的例子:
exit()
调用线程TerminateProcess()
(在Windows中)答案 0 :(得分:7)
这是每个C ++程序员应该知道的一个案例:
#include <stdio.h>
class EmbeddedObject {
private:
char *pBytes;
public:
EmbeddedObject() {
pBytes = new char[1000];
}
~EmbeddedObject() {
printf("EmbeddedObject::~EmbeddedObject()\n");
delete [] pBytes;
}
};
class Base {
public:
~Base(){
printf("Base::~Base()\n");
}
};
class Derived : public Base {
private:
EmbeddedObject emb;
public:
~Derived() {
printf("Derived::~Derived()\n");
}
};
int main (int argc, const char * argv[])
{
Derived *pd = new Derived();
// later for some good reason, point to it using Base pointer
Base* pb = pd;
delete pb;
}
~Base()
将被调用,但~Derived()
不会。这意味着~Derived()
中的代码不会执行。它可能需要做一些重要的事情。同样它的EmbeddedObject
的析构函数应该被自动调用但不是。因此,EmbeddedObject
没有机会释放其动态分配的数据。这会导致内存泄漏。
解决方案,在课程Base
virtual
中创建析构函数:
class Base {
public:
virtual ~Base() {
}
};
对上述程序进行一次更改意味着将在此oder中调用所有析构函数:Derived::~Derived()
,EmbeddedObject::~EmbeddedObject()
,Base::~Base()
阅读一般的析构函数。与您提到的其他方案相比,这类问题更容易引起您的关注。例如,在断电的情况下,所有安全清理的赌注通常都会关闭!
在C ++中,我们可以很好地控制按照我们希望它们发生的顺序执行析构函数的调用,这是个好消息。但是,在您编写的程序中,如果您不够仔细,可能会泄露对象并且不会被删除。
答案 1 :(得分:4)
不会为无限循环范围之外的对象调用析构函数。
答案 2 :(得分:2)
如果使用placement new创建对象,则不会自动调用此对象的析构函数。
答案 3 :(得分:1)
来自显而易见的事物,即exit(),kill signal,power failure等。
有一些非常常见的编程错误会阻止析构函数被调用。
1)使用创建动态对象数组
object* x = new object[n]
,但使用delete x
而非delete[] x;
2)而不是在对象上调用 delete()而不是调用 free()。虽然通常释放内存,但不会调用析构函数。
3)假设您有一个应该声明虚拟析构函数的对象层次结构,但由于某种原因不是。如果其中一个子类实例被转换为层次结构中的不同类型然后被删除,则它可能不会调用所有析构函数。
答案 4 :(得分:0)
在由于抛出异常而被调用的另一个析构函数中抛出异常。