C++ 不带std::move的右值引用

C++ 不带std::move的右值引用,c++,c++11,move,rvalue-reference,move-constructor,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&; au

我有以下课程

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;
};
由此产生的行为对我来说是可以理解的。在第一次调用中,构造一个小部件,然后调用move构造函数,并在临时小部件上调用析构函数

第二个调用也执行相同的操作,除了调用move赋值操作符而不是move构造函数。 离开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
它将被移动。然而,编译器只是执行。使用
-fno elide构造函数编译,您将看到对move构造函数的调用


无论何时显式使用
std::move
移动prvalue,都不允许编译器执行省略;这就是为什么在第一个代码段中可以看到move构造函数在运行。这就是为什么尝试使用
std::move
作为返回来“帮助”编译器几乎总是一个坏主意(除非您真的想返回右值引用)。

(widgeht())
是一个prvalue,即右值,因此它会被移动(如果可能的话)
std::move
不移动,它只是更改表达式的值类别。如果该表达式具有相应的值类别,那么它是多余的。括号是必需的,否则,表达式将作为指向不带参数并返回
小部件的函数指针进行计算。可能是您的编译器正在为您优化某些构造并进行复制吗?请尝试使用
-fno elide构造函数进行编译。您的副本将被删除(只有当
c
由非引用指定的临时文件初始化时,才能使用)。是的,额外的参数是必要的。否则,它是一个函数声明,而不是对象定义。@BenjaminLindley你说得对,我编辑了它。出于某种原因,我错误地认为
widget
是一个对象,而不是类的名称。