没有std :: move的Rvalue引用

时间:2015-05-05 16:01:40

标签: c++ c++11 move rvalue-reference move-constructor

我有以下课程

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上试过这个。

1 个答案:

答案 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作为返回来尝试“帮助”编译器几乎总是一个坏主意(除非你真的想要返回一个右值引用)。