rvalue引用没有std ::移动

Rvalue references without std::move

本文关键字:移动 std 引用 rvalue      更新时间:2023-10-16

我有以下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;
};

最终的行为对我来说是可以理解的。在第一个呼叫中,构造了一个小部件,然后调用移动构造函数,并在临时小部件上调用破坏者。

第二个呼叫也相同,期望调用移动分配运算符,而不是移动构造函数。离开主要方法,在c上调用了驱动器。


现在是有趣的部分:

#include "widget.h"
auto main() -> int {
    widget c((widget()));
    c = widget();
    return 0;
};

如果我省略了std::move的呼叫,则第一种情况会停止工作,并且仅导致一个构造函数调用。而第二种情况仍然像以前一样工作。

我在这里想念什么?为什么这两个函数调用对其参数的处理方式有所不同?我在GCC和Clang上尝试了一下。

widget()是纯rvalue(prvalue),因此在行中

widget c((widget())); // use widget c{widget()} or c{widget{}} for more clear code

它将被移动。但是,编译器只是执行复制/移动省略。用-fno-elide-constructors编译,您会看到对移动构造函数的所有荣耀的呼叫。

每当您明确使用std::move移动Prvalue时,您都不允许编译器执行elision;这就是为什么您会在第一个片段中看到MOVE构造函数。这就是为什么尝试使用std::move作为返回来"帮助"编译器几乎总是一个坏主意(除非您真的想返回rvalue参考)。