这是谁的析构函数?

3
在下面的代码中:
#include <string>
#include <iostream>

struct S {
    std::string a;
    int b;

    S(const S&) = default;
    S(S&&) = default;
    S& operator=(const S&) = default;
    S& operator=(S&&) = default; // not required here but should be added for completeness

    ~S() {
        std::cout << a << " " << b << std::endl;
    }
};

S f(S arg) {
    S s0{};
    S s1(s0); //s1 {s0}; in the book
    s1 = arg;
    return s1;
}

int main()
{
    S s3{"tool",42};
    f(s3);
}

我得到了以下输出(我用我的推理进行了注释):
 42 //???
 0  // s0 is destroyed
tool 42 // arg is destroyed
tool 42 // return value of f() is destroyed
tool 42 // s3 is destroyed

谁的析构函数会输出42?我不理解。

1
我似乎无法重现这个问题。您能告诉我们您使用的平台、编译器以及编译命令行吗? - SirDarius
cnr - WhozCraig
我能够复制所有内容,除了第一行的 "42"。你肯定是在使用 C++11,整个“Default”业务...。语言: C++11 创建时间: 0 秒前 可见性: 公共 - ha9u63a7
也无法复现 - 在我看来似乎没问题。我得到了我期望的输出,而不是上面显示的内容。 - Elemental
http://coliru.stacked-crooked.com/a/23646fe53ce8ede2 - Dean
1个回答

2

自动变量按声明的反向顺序销毁,因此所指示的析构函数是s1的析构函数。

在程序中该值为{"", 42}的原因是f的返回值正在进行移动构造初始化;也就是说,s1被视为xvalue。这遵循了[class.copy]/32的规则:

当满足拷贝操作的省略条件或者除了源对象是函数参数之外满足其余省略条件时,并且要拷贝的对象由lvalue指定,则为选择复制构造函数而首先按照该对象被rvalue指定来执行重载决议。


有趣的是,例如通过G++的-fno-elide-constructors选项触发此行为,该选项禁用了这种特定的优化。 - SirDarius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接