微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从右值引用合格成员函数按值还是按右值引用返回?

如何解决从右值引用合格成员函数按值还是按右值引用返回?

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;
};

这似乎很清楚:现在non_temp_obj.data()调用一个重载,并返回对该对象的成员的引用,该对象的成员在此之后仍然存活,而make_temp_obj().data()按值返回一个死亡的对象的成员该表达式完成后。

这是我的第一个问题:关于&&超载,考虑到我们正在按价值返回,为什么选择return std::move(values);而不仅仅是return values;

但是,在errata中,迈耶斯写道

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

我认为是建议更改

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

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

但是我不明白原因,特别是考虑到this answer,这使我确信书的版本是正确的,勘误是错误的。

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

解决方法

values是一个对象成员,是一个左值,因此,如果直接使用return values,它将被复制到返回值,而不移动。 && ref限定的重载点是避免产生不必要的副本。 return std::move(values)通过将values强制转换为右值来实现此目的,以便将其从中移出而不是复制。

对于您问题的第二部分:两者都有其优点和缺点。正如您链接的答案所指出的那样,从&&重载按值返回避免了生命周期问题,因为如果立即将引用绑定到它,则返回的对象的生命周期将延长。另一方面,按值返回可能会意外破坏values的值。例如:

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.
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。