首页 > 解决方案 > 从右值引用限定的成员函数按值或按右值引用返回?

问题描述

Effective Modern C++的第 12 条中,Scott Meyers 编写了以下类来展示在引用限定符上重载成员函数是多么有用:

class Widget {
public:
    using DataType = std::vector<double>;
    …
    DataType& data() &            // for lvalue Widgets
    { return values; }            // return lvalue

    DataType data() &&            // for rvalue Widgets
    { return std::move(values); } // return rvalue
    …
private:
    DataType values;
};

这似乎很清楚: nownon_temp_obj.data()将调用第一个重载并返回对之后仍然存在的对象成员的引用,而make_temp_obj().data()通过值返回对象的成员,该成员在该表达式完成后立即死亡。

这是我的第一个问题:关于&&重载,考虑到我们按值返回,为什么return std::move(values);不只是?return values;

然而,在勘误表中,迈耶斯写道

让成员函数的右值引用重载data返回一个右值的更好方法是让它返回一个右值引用。这将避免为返回值创建临时对象,并且与data第 84 页顶部附近的原始接口的按引用返回一致。

我解释为建议改变

    DataType data() &&
    { return std::move(values); }

    DataType&& data() &&
    { return std::move(values); }

但我不明白原因,特别是鉴于这个答案几乎让我相信这本书的版本是正确的,而勘误表是错误的。

所以我的第二个问题是:谁是对的?

标签: c++c++11move-semanticsrvalue-referenceref-qualifier

解决方案


values is an object member and an lvalue, so if you just return values directly, it will be copied to the return value, not moved. The point of the && ref-qualified overload is to avoid making an unnecessary copy. return std::move(values) accomplishes this by casting values to an rvalue, so that it gets moved from instead of copied.

For the second part of your question: both have their advantages and disadvantages. As the answer you linked notes, returning by value from the && overload avoids lifetime issues, since the returned object will have its lifetime extended if a reference is immediately bound to it. On the other hand, returning by value could destroy the value of values unexpectedly. For instance:

DataType Widget::data() &&
{ return std::move(values); }

void func() {
    Widget foo;
    std::move(foo).data(); // Moves-constructs a temporary from
                           // foo::value, which is then immediately
                           // destroyed.
    auto bar = foo.data(); // Oops, foo::value was already moved from
                           // above and its value is likely gone.
}

推荐阅读