【问题标题】:Rvalue references without std::move [duplicate]没有 std::move 的右值引用
【发布时间】:2015-07-15 11:32:02
【问题描述】:

我有以下课程

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

【问题讨论】:

  • (widghet()) 是一个prvalue,即一个右值,因此它被移动(如果可能的话)。 std::move 不动,它只是改变了表达式的值类别。如果该表达式无论如何都有相应的值类别,那就是多余的。
  • 括号是必需的,否则表达式被评估为指向不带参数并返回widget的函数的函数指针。
  • 会不会是您的编译器正在为您优化一些结构和副本?
  • 尝试使用-fno-elide-constructors 编译。您的副本正在被省略(仅当 c 由未由引用指定的临时初始化时才有效)。

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


【解决方案1】:

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 时,您都不允许编译器执行省略;这就是为什么您在第一个 sn-p 中看到移动构造函数的原因。这就是为什么尝试通过使用 std::move 作为返回值来“帮助”编译器几乎总是一个坏主意(除非你真的想返回一个右值引用)。

【讨论】:

  • 是的,额外的括号是必要的。否则,它是一个函数声明,而不是一个对象定义。
  • @BenjaminLindley 你是对的,我编辑了它。出于某种原因,我错误地认为widget 是一个对象,而不是类的名称。
猜你喜欢
  • 1970-01-01
  • 2021-08-26
  • 2015-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
  • 2013-06-13
相关资源
最近更新 更多