【问题标题】:When should we declare rvalue refs if they actually need std::move?如果右值引用确实需要 std::move,我们应该何时声明它们?
【发布时间】:2019-11-14 10:15:00
【问题描述】:

正如许多其他帖子所解释的,将一个变量声明为右值引用并保证它将调用移动赋值运算符,仅使用 std::move(即,转换为相同的右值引用) 会做的。例如:

struct A
{
    A& operator=(A&& l_other) { std::cout << "move" << std::endl; }
    A& operator=(A&  l_other) { std::cout << "copy" << std::endl; }
};

A a;

// does not print anything, compiler does nothing here!
A&& b = std::move(a);

// prints "copy", not "move"
a = b;

// prints "move", but needs std::move()
a = std::move(b);

似乎将b 定义为A&amp;&amp; 在那一刻不会移动任何东西。之后,a = b 不会自动移动b,即使右侧部分被定义为A&amp;&amp;,正如其他帖子所解释的那样。我们需要显式调用std::move(b) 来移动b

我的问题是,将变量定义为 A&amp;&amp; 有什么用处?我可以完美地将其定义为 A&amp; 并将其移动完全相同。

【问题讨论】:

  • 要解决为什么需要std::move,请参阅std::move - 特别是注释中的这句话:“右值引用变量的名称是左值,必须转换将 xvalues 绑定到接受右值引用参数的函数重载”。是的,这很复杂:)
  • @Victor 赋值a = b 触发复制赋值的原因是因为b 实际上是一个lvalue,类型为rvlaue reference to A。声明右值引用的原因是为了捕捉,嗯,右值,你不能用A&amp;捕捉。
  • 当您想与A&amp; 区分开来时声明它们,即作为参数。我想不出在任何情况下您都希望 A&amp;&amp; 作为局部变量,而不是 AA &amp;
  • R 值引用(例如您的情况下的 A&amp;&amp;)很少在函数体中声明。它们主要用作函数参数。无论如何,一个简单的经验法则是任何有名字 (b) 的东西都是左值。
  • 这可能会让你感兴趣:stackoverflow.com/q/45843974/2805305

标签: c++ move-semantics rvalue


【解决方案1】:

我的问题是,将变量定义为 A&& 有什么用处?我可以将它完美地定义为 A& 并完全一样地移动它。

如果将命名变量传递给函数并像这样在没有警告的情况下进行修改,那将非常令人不快,并可能导致令人不快的调试会话。

当您使用右值引用时,类型系统会强制执行有用的保证。引用绑定到一个右值,因此修改它不会违反任何人的假设(无论如何它很快就会消失)。或者您已明确允许离开它。调用上下文不能意外地授予您修改左值的权限,它必须通过显式强制转换 (std::move) 进行。

显式优于隐式。并且让右值引用以它们的方式与类型系统交互有助于确保移动不会使对象处于意外状态。看一眼调用上下文就会发现,传递给函数的变量可能处于未知状态,因为它被明确地包围在对 std::move 的调用中。

这就是右值引用的好处。

【讨论】:

    【解决方案2】:

    可以这样想:涉及两方:对象的生产者(受引用约束)和引用的消费者。

    引用的类型定义了允许进入引用(生产者)的内容,而不是变量(消费者)中的

    对于消费者来说,它是哪种参考没有区别。

    对于生产者而言,右值引用是一个标志,表明只能绑定一个可消耗的值(临时值或 xvalue,例如 str::move 的结果)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      相关资源
      最近更新 更多