In Effective Modern C++, Item 12, Scott Meyers writes the following class to show how useful overloading member functions on the reference qualifiers can be:
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;
};
This seems clear: now non_temp_obj.data() will call the first overload and return a reference to a member of an object which is still alive afterwards, whereas make_temp_obj().data() returns by value a member of an object which dies as soon as that expression is done.
Here's my first question: as regards the && overload, why return std::move(values); and not just return values;, considering we are returning by value?
In the errata, however, Meyers writes
A better way to have the rvalue reference overload of the
datamember function return an rvalue is to have it return an rvalue reference. That would avoid the creation of a temporary object for the return value, and it would be consistent with the by-reference return of the originaldatainterface near the top of page 84.
which I interpret as suggesting to change
DataType data() &&
{ return std::move(values); }
to
DataType&& data() &&
{ return std::move(values); }
but I don't understand the reason, especially in light of this answer which pretty much convinces me that the book version is correct and the errata is wrong.
So my second question is: who's right?
valuesis an object member and an lvalue, so if you justreturn valuesdirectly, 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 castingvaluesto 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 ofvaluesunexpectedly. For instance: