在Scott Meyer的新书中,他提出了rvalue引用限定符的示例用法,如下所示:
class Widget {
private:
DataType values;
public:
DataType& data() & { return values; }
DataType data() && { return std::move(values); } // why DataType?
};
那样:
auto values = makeWidget().data();
move-constructs values
而不是复制构造它。
为什么rvalue-ref-qualified data()
会返回DataType
而不是DataType&&
?在这种情况下,auto
仍然会推断DataType
(尽管decltype(auto)
不会 - 但这不是唯一的理由更喜欢返回值而不是ravlue ref)。 This高度投票的回答会返回一个右值ref,这对我来说在概念上更有意义。
答案 0 :(得分:7)
DataType data() && { return std::move(values); } // why DataType?
auto values = makeWidget().data();
保存返回值的临时值将通过move-constructor初始化,从move(values)
进行复制初始化。
然后临时初始化values
,但由于makeWidget().data()
是一个rvalue(准确的prvalue),所以再次调用move-constructor - 将temporary作为其参数。
现在考虑copy-elision:
当无名的临时,未绑定任何引用时,将被移动 或者复制到同一个cv-unqualified类型的对象中 复制/移动被省略。当构建临时建筑时,它就是 直接在存储器中构造,否则它将被移动 或复制到。当无名临时是返回的参数时 声明,复制省略的这种变体称为RVO,"返回值 优化"
所以第二步将(大概)完全省略,只留下一个 - 我们原本应该拥有的那个,返回类型是右值参考。
返回右值引用的问题是,如果我们写
auto&& values = makeWidget().data();
values
将悬空,因为将xvalue绑定到引用并不会延长任何生命周期。当我们返回对象类型时,临时寿命会延长。
答案 1 :(得分:-4)
auto&&
将被破坏。在这种特殊情况下,链接的答案被打破了。
这里的核心问题是你可以在左值或右值上重载,但实际上你可能想知道三个值类别 - 值,左值和右值。调用成员函数时,C ++不区分值和右值,因此您无法知道返回右值引用是否正确。无论你做出哪个决定,都可以很容易地构建不起作用的例子。