Optimization for r-values
Comparison of void setData(std::string arg) and void setData(std::string&& arg) . In the first case, I assume that setData moves data in place
class Widget { std::string data; public: void setData(std::string data) { this->data = std::move(data); } };
And if we call it that
w.setData(std::move(data));
we get one call to the move constructor to build the function argument and one call to the move assignment operator to move the data to the member variable. So, just two steps.
But if we overload the r-value references, for example:
class Widget { std::string data; public: void setData(std::string&& data) { this->data = std::move(data); } };
You get only one call forwarding assignment operator. You could say, "But traffic is cheap!" what could be true. In some cases, they are not cheap (for example, std::array ), and in the case of std::string most compilers implement small string optimization (SSO), so for small strings moving is not cheaper than a copy.
Optimization for l-values
The argument for passing by value often is that you can optimize for both l-values ββand r-values ββwithout having to provide two overloads void setData(const std::string& arg) and void setData(std::string&& arg) So let's compare what happens if we pass the l-value to void setData(std::string arg) vs void setData(const std::string& arg) . In the first case, you will receive one unconditional copy, and then one move. In the second case, you get only one job. The additional transfer destination is probably small, but it is possible that an unconditional copy is much more expensive than the destination. If you call setData more than once on the same object, the assignment may reuse the existing capacity and avoid re-allocation. An unconditional copy will always perform the selection.
Perhaps these considerations are insignificant in practice, but you should be aware of them.
Documentation / Securing Transfer of Ownership
Another use of r-value reference parameters is to document / enforce ownership. Let's say you had a large object that you can copy and move, then you can only provide void setData(BigData&& data) for forced movement. In addition to making it less likely that someone accidentally makes a copy, it also documents that we take responsibility for the data. You do not need to move the entire object as well, you can just steal part of the object.