我有以下课程
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上试过这个。
答案 0 :(得分:12)
widget()
是纯粹的右值(prvalue),所以在行
widget c((widget())); // use widget c{widget()} or c{widget{}} for more clear code
它会被移动。但是,编译器只执行copy/move elision。使用-fno-elide-constructors
进行编译,您将看到对移动构造函数的所有荣耀的调用。
每当你明确使用std::move
移动prvalue时,你就不允许编译器执行省略;这就是你在第一个片段中看到移动构造函数的原因。这就是为什么通过使用std::move
作为返回来尝试“帮助”编译器几乎总是一个坏主意(除非你真的想要返回一个右值引用)。