【问题标题】:Return value or rvalue reference?返回值还是右值引用?
【发布时间】:2014-12-08 22:33:02
【问题描述】:

在 Scott Meyer 的新书中,他提出了一个右值引用限定符的示例用法,如下所示:

class Widget {
private:
    DataType values;

public:
    DataType& data() &  { return values; } 
    DataType  data() && { return std::move(values); } // why DataType?
};

这样:

auto values = makeWidget().data();

移动构造 values 而不是复制构造它。

为什么右值引用限定的data() 返回DataType 而不是DataType&&?在这种情况下,auto 仍会推断出DataType(尽管decltype(auto) 不会 - 但这不是更喜欢返回值而不是 ravlue ref 的唯一原因)。 This 高度投票的答案返回一个右值引用,这在概念上对我来说更有意义。

【问题讨论】:

  • “投票率高的答案”正确建议按值返回,再次阅读
  • @bobah 它说“您返回右值引用的情况在其他情况下是个好主意。”在提议之前Beta_ab && getAB() && { return move(ab); }...

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


【解决方案1】:
DataType data() && { return std::move(values); } // why DataType?

auto values = makeWidget().data();

保存返回值的临时变量将通过移动构造函数初始化,从move(values)复制初始化。

然后临时初始化values,但由于makeWidget().data() 是一个右值(准确地说是纯右值),因此再次调用移动构造函数 - 将临时值作为其参数。

现在考虑copy-elision

当一个未绑定到任何引用的无名临时对象将被移动时 或复制到相同 cv 非限定类型的对象中, 复制/移动被省略。当那个临时的被建造时,它是 直接在仓库中建造,否则它会被移动 或复制到。当无名临时变量是返回的参数时 声明,这种复制省略的变体被称为 RVO,“返回值 优化”。

因此,第二步将(可能)被完全忽略,只剩下一个 - 如果返回类型是右值引用,我们无论如何都会拥有这个。

返回右值引用的问题在于,如果我们写

auto&& values = makeWidget().data();

values 将悬空,因为将 xvalue 绑定到引用不会延长任何东西的生命周期。当我们返回对象类型时,临时对象的生命周期就会延长。

【讨论】:

  • 所以唯一的原因是因为与auto&&的悬空?在任何一种情况下,我们只会完成一个动作......从成员 values 到对象 values 的一个动作(我应该在问题中以不同的方式命名它们)。
  • @LightnessRacesinOrbit 引用不是临时的。
  • @R.MartinhoFernandes:makeWidget() 所指的对象可能是。但这没关系;这不受任何约束。
  • @Barry 在我看来,auto&& 作为变量类型在返回为其完整对象取别名的右值引用时并不是主要关注点。虽然这会导致基于范围的 for 循环出现问题(auto&& 被隐藏),但也要考虑函数参数(转发 refs、rvalue refs 和 lref-to-const)
  • @Barry Who is to blame for this range based for over a reference to temporary? ;对于函数参数,我可能错了,因为构建示例并不简单。在任何情况下,临时至少会一直存在到完整表达式的末尾,因此只有在临时创建范围内定义变量时才会出现问题,并且可能对于花括号初始化列表(IIRC 每个初始值设定项都是完整表达式)。
【解决方案2】:

auto&& 如果返回右值引用,将被破坏。在这种特殊情况下,链接的答案被破坏了。

这里的核心问题是您可以重载左值或右值,但实际上您可能想了解三个值类别 - 值、左值和右值。 C++在调用成员函数的时候不区分值和右值,所以你无法知道返回右值引用是否正确。无论您做出何种决定,都可以轻松构建不起作用的示例。

【讨论】:

  • 你的意思是左值、xvalue和prvalue?
  • 如果您愿意,您可以选择“最大程度的混淆”,但我更愿意将其保留在“非语言律师居住地”的领域。
  • 老实说,我不知道您对每个价值类别名称的确切含义。我会坚持使用我看到其他人(不仅仅是标准)使用的术语。
  • 链接的答案如何“损坏”?在任何东西都悬空之前,他会立即移动构造一个新对象。
猜你喜欢
  • 2011-11-10
  • 2018-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-03
相关资源
最近更新 更多