As you can see, ByVal produces 1 extra move compared to pair of
reference overloads. So the question is: is it worth it? When would
you create two overloads instead of one simple pass by value function?
+1 Most people who ask this question don't bother to do the analysis. So you get my upvote for doing your own homework. :-)
Whether it is worth it or not is going to depend on the cost of the move constructor, and on how many arguments the function takes. On one extreme, if the move constructor isn't that fast, you may care a lot about eliminating them (favoring the const&, && overload solution). At the other extreme, if your function has 4 parameters, each of which need lvalue/rvalue treatment, you may not be willing to write 16 overloads to cover all the cases. That's a lot of code to maintain, and the inherent code complexity is an invitation for bugs. So the by-value approach looks more attractive (which requires no overloads).
So imho, there is no general answer to the "is it worth it" question. The best answer is to equip yourself with the knowledge about the cost of each solution, as you have already done, and make an engineering judgement on a case by case basis.
Update
In the case of vector<T>::push_back
imho the const&, && overload solution is worth it. There is only one parameter, and we have no idea how expensive the move constructor is. Indeed, we don't even know if there is a move constructor. Modifying your experiment to test out that latter case (removing the move constructor):
ByVal(a);
A Copy
A Copy
ByLCRef(a);
A Copy
Do you want to pay one copy or two to copy your A
into the vector
?
I.e. the less you know about your parameters, the more you have to lean towards the performance side, especially if you're writing something as heavily used as std::vector
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…