析构函数如何在简单程序中工作?

How do destructors work in a simple program?

我不明白这个程序的输出:

class A {
public :
    A()  { cout << "A()"  << endl; }
    ~A() { cout << "~A()" << endl; }
};

A f (A & a) { 
    return a;
}

int main() {
    A a ;
    a = f(a);

    return 0;
}

我预计

A()
~A()

因为我只创建了一个 A 对象:a。然而,输出是

A()
~A()
~A()

你知道这是为什么吗?


跟进问题

好的,所以每当调用 f 时,我都会构造一个 A 的副本,所以我有 1 次调用复制构造函数和一次调用析构函数...

现在说我的主要功能是:

int main() {
    A a ;
    A b = f(a);
    cout << "returning 0" << endl;
    return 0;
}

我希望输出是

A(),
A(const A &) (for using f(a))
~A()         (for deleting temporary f(a))
returning 0
~A()         (destroying B)
~A()         (destroying A)

但是输出是

A() 
A(const& A) 
returning 0
~A()
~A()

这是为什么?

您只显式创建了一个对象,但您在这里创建了一个对象:

A f (A & a) { return a ;} //when returning A

当您复制对象以将其从 f 传回时,该副本由默认的复制构造函数构造,因为您没有提供复制构造函数。 如果您将 class 更改为:

class A {
public :
    A () { cout << "A() " << endl;}
    A (const A &) { cout << "A(const &) " << endl;}
    ~A () { cout << "~A ()" << endl; }
};

您将看到正在调用复制构造函数(因为您提供了一个)。

follow-up 问题的答案。

析构函数与构造函数配对。为什么你期望两个建筑和三个破坏?这在正确的程序中是不可能的。

A b = f(a);

不是赋值(与 a = f(a) 相反),而是构造(copy initialization). You don't see a construction and destruction of a temporary object here thanks to the return value optimization (RVO):允许编译器省略不必要的副本并将 b 构造为如果按 A b(a);.

在 C++17 之前,此机制是可选的。您可以 compile 使用带有 -std=c++11 -fno-elide-constructors 选项的 GCC 来发现临时代码:

A()              construct (a)
A(const A&)      construct a temporary copy of (a)
A(const A&)      construct (b) from that temporary
~A()             destruct that temporary
returning 0 
~A()             destruct (b)
~A()             destruct (a)

从 C++17 开始,这种类型的复制省略是强制性的,因此您将始终只看到两种构造和破坏:

A()              construct (a)
A(const A&)      construct (b) from (a)
returning 0 
~A()             destruct (b)
~A()             destruct (a)