程序何时不在c ++中调用析构函数?

时间:2016-02-17 21:31:41

标签: c++ destructor

所以这是代码:

#include <iostream>

using namespace std;

class C {
public:
    C() {i = 6; cout << "A:" << i << endl;}

    C(int i0) {i = i0; cout << "B:" << i << endl;}

    ~C() {cout << "C:" << i << endl;}
private:
    int i;
};

int main(int argc, char* argv[]) {
    cout << "X" << endl;
    C *c = new C;
    cout << "Y" << endl;
}

由于某种原因,该代码的输出是

X
A:6
Y

由于某种原因,一旦到达代码末尾就不会调用析构函数(C:6)。这是为什么?此代码也调用析构函数:

#include <iostream>

using namespace std;

class C {
public:
    C() {i = 0; cout << "A:" << i << endl;}

    C(int i0) {i = i0; cout << "B:" << i << endl;}

    ~C() {cout << "C:" << i << endl;}
private:
    int i;
};

int main(int argc, char* argv[]) {
    cout << "X" << endl;
    C c;
    cout << "Y" << endl;
}

3 个答案:

答案 0 :(得分:10)

因为你忘了写

delete c;

如果您只是在程序中继续而不删除用new实例化的变量,则会导致内存泄漏。

编辑,因为您修改了问题:

如果你写的话

C c;
C c{1};
C c = C{1};

您创建具有自动存储持续时间的变量。一旦在退出中声明它的函数它将超出范围(或者更精确:一旦在退出时声明它的块)。在这种情况下,将自动调用构造函数。

如果你写

C* c = new C{};

你创建一个指向(新)C的指针。指针本身具有自动存储持续时间,这意味着c也将超出范围。但是指针只保存C类对象的地址。只有在调用delete c;时才会删除此对象。如果你不打电话给删除,你的程序会忘记&#34;对象的地址,但它不释放内存或销毁对象。那是一次记忆泄漏 但是一旦程序结束,所有内存都被释放(不调用析构函数),所以在你的小例子中你不会注意到。

答案 1 :(得分:5)

非常很少需要您自己直接调用析构函数。

当一个对象被销毁时,通过超出堆栈实例的范围或者通过delete d来获取堆实例,自动调用析构函数。因此,您的析构函数未被调用的事实告诉您一些事情:对象正在丢失或泄露。

new从堆内存创建对象的新实例,并打开一个契约,当不再需要该对象时,您将负责调用delete将其返回堆中。 (或delete []如果你分配一个数组)

在您的代码中,您永远不会delete您创建的实例。

#include <iostream>

using namespace std;

class C {
public:
    C() : m_i(6) { cout << "A:" << m_i << endl;}

    C(int i_) : m_i(i_) { cout << "B:" << m_i << endl;}

    ~C() {cout << "C:" << m_i << endl;}
private:
    int m_i;
};

int main(int argc, char* argv[]) {
    cout << "X\n";
    C* c = new C;
    C stackC;
    cout << "Y\n";
    delete c;
    cout << "Z\n";
}

现场演示:http://ideone.com/iuZim4

答案 2 :(得分:0)

当您使用'new'分配动态变量时,对象实例的生命周期以1)删除或2)进程终止或3)系统重置结束。

在您的代码中,程序在'delete c;'之前终止。被调用,因此进程不会调用dtor。

当操作系统终止进程时,进程使用的任何动态内存都会被“回收”。此操作系统'回收'也不会调用dtor。

当系统关闭或重启时,软件停止运行,因此不会调用dtor。

在没有析构函数调用的情况下分配对象在嵌入式系统中很常见。