函数返回的类的析构函数

wis*_*spi 3 c++ destructor g++ class

我有以下代码:

#include <stdio.h>

class Foo {
    public:
    int a;
    ~Foo() { printf("Goodbye %d\n", a); }
};

Foo newObj() {
    Foo obj;
    return obj;
}

int main() {
    Foo bar = newObj();
    bar.a = 5;
    bar = newObj();
}
Run Code Online (Sandbox Code Playgroud)

当我编译g++并运行它时,我得到:

Goodbye 32765
Goodbye 32765
Run Code Online (Sandbox Code Playgroud)

打印的数字似乎是随机的。

我有两个问题:

  1. 为什么析构函数被调用两次?
  2. 为什么5第一次不打印?

我来自C的背景,因此来自printf,并且在理解析构函数,调用它们的时间以及如何从函数返回类时遇到了麻烦。

Ann*_*nyo 11

Let's see what happens in your main function :

int main() {
    Foo bar = newObj();
Run Code Online (Sandbox Code Playgroud)

Here we just instantiate a Foo and initialize it with the return value of newObj(). No destructor is called here because of copy elision: to sum up very quickly, instead of copying/moving obj into bar and then destructing obj, obj is directly constructed in bar's storage.

    bar.a = 5;
Run Code Online (Sandbox Code Playgroud)

Nothing to say here. We just change bar.a's value to 5.

    bar = newObj();
Run Code Online (Sandbox Code Playgroud)

Here bar is copy-assigned1 the returned value of newObj(), then the temporary object created by this function call is destructed2, this is the first Goodbye. At this point bar.a is no longer 5 but whatever was in the temporary object's a.

}
Run Code Online (Sandbox Code Playgroud)

End of main(), local variables are destructed, including bar, this is the second Goodbye, which does not print 5 because of previous assignment.


1 No move assignment happens here because of the user-defined destructor, no move assignment operator is implicitly declared.
2 As mentioned by YSC in the comments, note that this destructor call has undefined behavior, because it is accessing a which is uninitialized at this point. The assignment of bar with the temporary object, and particularly the assignment of a as part of it, also has undefined behavior for the same reasons.