为什么析构函数在这里被调用两次?

Why does destructor get called twice in here?

#include <iostream>

struct ABC{
    int A;
    ABC(int i = 1) : A(i) {}
    ~ABC() {
        std::cout << A << std::endl;
    }
    void destruct() {
        delete this;
    }
};

int main() {
    ABC A1(2);
    A1.destruct();
    return 0;
}

Output:
2
2

我有这段代码,我在其中尝试手动删除结构变量。这样做,我意识到析构函数在这里被调用了两次。为什么会这样?为什么在调用 destruct() 时它没有被删除?

delete this 调用导致 undefined behaviour,这意味着任何事情都可能发生。

delete 只能用于 new 创建的对象。


对于具有非平凡析构函数的自动对象(例如您的 A1),不可能 "destroy them early" 除非您还在同一位置之前创建另一个 ABC范围结束。换句话说,您不能 "turn off" 作用域结束时发生的销毁过程。

这是 RAII 工作加上你在一个物体上自杀。在对象上调用析构函数几乎总是错误的!两次调用析构函数总是错误的,因为它会调用未定义的行为。

你必须明白 C++ 正在为你处理内存,如果你让它:

struct Foo{};
int main() {
    Foo f;               // automatic storage, gets destroyed
                         // when object gets out of scope

    Foo* g = new Foo();  // heap allocated
    delete g;            // only here you have to delete
}

请记住:不要 delete 任何不是通过 new 创建的内容(感谢 Mike Vine 的评论)。除非需要,否则不要使用(裸)堆分配。

Why isn't [my object] getting deleted when destruct() is called?

当一个对象在 C++ 中被析构时,并不意味着该对象消失了。这意味着析构函数中的清理代码得到执行,从那时起对对象成员的任何访问都是无效的。

当您调用 destruct() 时,您尝试通过调用 delete 来释放对象的内存。这本身就是未定义的行为,因为您还没有用 new 分配对象。此调用导致第一个打印输出。

但是,由于您的对象位于自动内存中,因此当对象超出范围时,C++ 需要调用其析构函数。这是导致第二次打印输出的调用。

注意:您可以通过在动态内存中分配 A1 来修复您的代码:

int main() {
    ABC *A1 = new ABC(2);
    A1->destruct();
    return 0;
}

现在您得到一个打印输出 (demo)。但是,在成员函数中隐藏delete的做法值得商榷。

这里有两点需要考虑:-

1) 堆栈对象的析构函数在超出范围时将始终被调用。所以不用担心他们的重新分配。

2) 您不能也不应该对堆栈上分配的对象使用 delete。通常,只要您不确定这是否仅作为删除堆对象的结果执行并且之后您不引用该对象,您就不应该使用 delete this