I'm working through Stroustrup's "Tour of C v2". It's certainly not a C beginner's book, but enjoyable.
I've had a google and look through SO but no joy on this one.
Now, I thought I understood when the compiler can utilise a move constructor, but clearly I don't. Here I show the move constructor and the function that I thought would use it. It doesn't. Only if I explicitly use std::move. Why is this? My understanding was that the local r would be "moved" implicitly on return.
template<typename T>
Vector<T>::Vector(Vector<T> && a) // move constructor
:elem{a.elem},sz{a.sz}{
a.elem=nullptr;
a.sz=0;
}
template<typename T>
Vector<T> moveVectorAfterAdd(const Vector<T> & v1, const Vector<T> & v2){
Vector<T> r = v1 v2;
return std::move(r);
//return r;
}
int main(void) {
Vector<double> v1(1);
Vector<double> v2=v1;
Vector<double> v3=v2;
Vector<double> v4=moveVectorAfterAdd(v1,v2);
return 0;
}
(As a side note, lldb won't let me even set a break point in the move constructor despite compiling with no optimizations if I don't actually use std::move.)
Any and all clarifications gladly received!
CodePudding user response:
When do you need to explicitly call std::move and when not in cpp?
In short, and technically precise words: Use std::move when you have an lvalue that you want to be an rvalue. More practically: You would want to do that when there is a copy that you want instead to be a move. Hence the name std::move.
In the example, you return an automatic variable. There is no copy that can be avoided by using std::move because in the special case of returning an automatic variable, there will be a move even from an lvalue.
Here I show the move constructor and the function that I thought would use it. It doesn't.
Just because there is a move in the abstract machine, doesn't necessarily mean that there would be a call to the move constructor. This is a good thing because doing nothing can potentially be faster than calling the move constructor.
This is known as (Named) Return Value Optimization. Or more generally copy elision. Using std::move inhibits this optimization, so not only is it unnecessary in this case, but it is also counter productive.