c++ - 默认移动构造

标签 c++

本书The C++ Programming Language有这个关于默认操作的例子。我的问题集中在默认移动操作上。

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

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

之后它说:

The copy construction of s1 copies s0.a and s0.b. The return of s1 moves s1.a and s1.b, leaving s1.a as the empty string and s1.b unchanged. Note that the value of a moved-from object of a built-in type is unchanged. That’s the simplest and fastest thing for the compiler to do.

我认为这意味着如果我写:

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

既然s1的值被移动了,s1.a会变回“”而s1.b不变?那么当f()执行完,s1会被销毁吗? 我试图找到一种方法来测试我的猜测,但我找不到在函数执行后知道 s1 值的方法,因为它当然是本地的。我写了一个析构函数只是为了在它们被销毁之前找到值。

~S() {
    std::cout << a << " " << b << '\n';
}

输出是:

0 //values of s0?
tool 42
tool 42
tool 42

看来我的猜测是完全错误的,我完全看不懂课文。谁能更清楚地解释引文中的文字?

最佳答案

首先,通过定义析构函数,您禁用了隐式移动构造函数。您必须添加到您的代码中:

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

然后,无论如何 RVO 开始发挥作用。如其他答案所述,允许编译器省略对复制和移动构造函数的调用。在 GCC 和 clang 中,您可以通过添加 -fno-elide-constructors 编译器选项来禁用它。之后你会得到这个输出:

 42 // moved s1 (this can theoretically be different, because the value of s1.a is unspecified)
 0  // s0
tool 42 // arg
tool 42 // return value of f()
tool 42 // s3

Demo

关于c++ - 默认移动构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26732417/

相关文章:

c++ - BST 中大于给定 KEY 的节点数

c++ - boost::thread join 函数 block 调用线程

c++ - 循环依赖c++

c++ - 段错误(核心转储)错误未解决

c++ - 与 glfw 静态库的链接问题

c++ - 这个循环有什么问题吗?

C++:是否需要使用相同版本的 GCC 和 GDB 进行调试

c++ - 使用 MSBuild 目标文件时查看 VS C++ 项目中的有效属性?

c++ - 如何从 Lua 调用 C++ DLL 中的函数?

c++ - 如何获取 Python 异常文本