没有 std::move 的右值引用
Rvalue references without std::move
我关注class
class widget {
// The methods only print their name, i.e. c'tor, destructor etc.
public:
widget();
widget(const widget&);
widget(widget&&);
~widget();
auto operator=(const widget&) -> widget&;
auto operator=(widget&&) -> widget&;
};
我在下面的代码中使用了它
#include "widget.h"
auto main() -> int {
widget c(std::move(widget()));
c = std::move(widget());
return 0;
};
由此产生的行为对我来说是可以理解的。在第一次调用中构造一个小部件,然后调用移动构造函数并在临时小部件上调用析构函数。
第二次调用做同样的事情,期望调用移动赋值运算符而不是移动构造函数。
离开 main 方法,在 c
.
上调用析构函数
有趣的部分来了:
#include "widget.h"
auto main() -> int {
widget c((widget()));
c = widget();
return 0;
};
如果我省略对 std::move
的调用,第一种情况将停止工作并导致仅调用一次构造函数。而第二种情况仍然像以前一样工作。
我在这里错过了什么?为什么这两个函数调用以不同方式处理它们的参数?
我在 gcc 和 clang 上试过了。
widget()
是一个纯右值 (prvalue),所以在行
widget c((widget())); // use widget c{widget()} or c{widget{}} for more clear code
它将被移动。然而,编译器只是执行copy/move elision。使用 -fno-elide-constructors
进行编译,您将看到对移动构造函数的所有调用。
无论何时显式使用 std::move
移动纯右值,都不允许编译器执行省略;这就是为什么您会在第一个片段中看到正在运行的移动构造函数。这就是为什么通过使用 std::move
作为 return 来尝试 "help" 编译器几乎总是一个坏主意(除非你真的想要 return 右值引用)。
我关注class
class widget {
// The methods only print their name, i.e. c'tor, destructor etc.
public:
widget();
widget(const widget&);
widget(widget&&);
~widget();
auto operator=(const widget&) -> widget&;
auto operator=(widget&&) -> widget&;
};
我在下面的代码中使用了它
#include "widget.h"
auto main() -> int {
widget c(std::move(widget()));
c = std::move(widget());
return 0;
};
由此产生的行为对我来说是可以理解的。在第一次调用中构造一个小部件,然后调用移动构造函数并在临时小部件上调用析构函数。
第二次调用做同样的事情,期望调用移动赋值运算符而不是移动构造函数。
离开 main 方法,在 c
.
有趣的部分来了:
#include "widget.h"
auto main() -> int {
widget c((widget()));
c = widget();
return 0;
};
如果我省略对 std::move
的调用,第一种情况将停止工作并导致仅调用一次构造函数。而第二种情况仍然像以前一样工作。
我在这里错过了什么?为什么这两个函数调用以不同方式处理它们的参数? 我在 gcc 和 clang 上试过了。
widget()
是一个纯右值 (prvalue),所以在行
widget c((widget())); // use widget c{widget()} or c{widget{}} for more clear code
它将被移动。然而,编译器只是执行copy/move elision。使用 -fno-elide-constructors
进行编译,您将看到对移动构造函数的所有调用。
无论何时显式使用 std::move
移动纯右值,都不允许编译器执行省略;这就是为什么您会在第一个片段中看到正在运行的移动构造函数。这就是为什么通过使用 std::move
作为 return 来尝试 "help" 编译器几乎总是一个坏主意(除非你真的想要 return 右值引用)。