为什么自动对象的析构函数被调用两次?

Ste*_*ler 3 c++ destructor automatic-storage

(我的问题的答案涉及复制构造函数,但复制发生在从函数返回时,而不是在对另一个类的方法调用中.我实际上看到引用的可能重复,但没有从vector :: copy制作的副本中推断出来:) push_back我的函数在这里也复制了.也许我应该有.)

我试图了解自动对象的构造/破坏.我遇到了一些看起来很可疑的代码,所以我编写了自己的版本以努力理解它.简而言之,原始代码包含一个返回函数本地对象的函数(自动).这对我来说看起来不安全,所以我写了这个程序来探索它:

#include <stdio.h>

class Phantom
{
private:
    static int counter;
    int id;

public:
    Phantom()
    {
        ++counter;
        id = counter;
        printf("Phantom %d constructed.\n", id);
    };

    virtual ~Phantom()
    {
        printf("Phantom %d destructed.\n", id);
    };

    void speak()
    {
        printf("Phantom %d speaks.\n", id);
    };
};

int Phantom::counter = 0;

Phantom getPhantom()
{
    Phantom autoPhantom;

    return autoPhantom; // THIS CAN'T BE SAFE
}

int main()
{
    Phantom phantom;

    phantom = getPhantom();

    phantom.speak();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到这个输出:

Phantom 1 constructed.
Phantom 2 constructed.
Phantom 2 destructed.
Phantom 2 destructed.
Phantom 2 speaks.

这是输出中的第四行让我感到困惑.

main输入时会自动构建幻像1 .

getPhantom输入时会自动构建幻像2 .

幻影2在getPhantom退出时自动被破坏(这就是为什么我认为从它返回它getPhantom是不安全的).

但在那之后我很困惑.根据调试器,在第四行输出出现之前getPhantom已经返回.当第二次调用析构函数时,调用堆栈是这样的:Phantom

main
~Phantom

在托管语言中,我可以看到这一行:

phantom = getPhantom();
Run Code Online (Sandbox Code Playgroud)

会破坏Phantom 1,但它不会触及Phantom 2.这是C++,而不是Java.

是什么导致第二次调用Phantom 2的析构函数?

Res*_*ion 7

你返回一份副本.因此,变量in getPhantom()在范围的末尾被销毁,并且您的副本也具有id 2.这是因为在返回时它调用不增加id的复制构造函数(也是默认值).


Sam*_*hik 5

您忘记了正确说明:

  1. 复制构造函数.

  2. 分配运营商.

在这两种情况下,您将最终得到多个具有相同对象的对象id,两个对象最终id在析构函数中打印相同的对象.在复制构造函数的情况下,构造函数中不会打印任何消息,因为您没有定义自己的复制构造函数.对于赋值运算符,id构造函数中的赋值将被id另一个对象的副本覆盖.这就是这里发生的事情:

phantom = getPhantom();
Run Code Online (Sandbox Code Playgroud)

因此,您的会计错误.