Why do you use std::move when you have && in C++11? [duplicate]
First, there's probably a misconception in the question I'll address:
Whenever you see T&& t
in code (And T is an actual type, not a template type), keep in mind the value category of t
is an lvalue(reference), not an rvalue(temporary) anymore. It's very confusing. The T&&
merely means that t
is constructed from an object that was an rvalue 1, but t
itself is an lvalue, not an rvalue. If it has a name (in this case, t
) then it's an lvalue and won't automatically move, but if it has no name (the result of 3+4
) then it is an rvalue and will automatically move into it's result if it can. The type (in this case T&&
) has almost nothing to do with the value category of the variable (in this case, an lvalue).
That being said, if you have T&& t
written in your code, that means you have a reference to a variable that was a temporary, and it is ok to destroy if you want to. If you need to access the variable multiple times, you do not want to std::move
from it, or else it would lose it's value. But the last time you acccess t
it is safe to std::move
it's value to another T
if you wish. (And 95% of the time, that's what you want to do). All of this also applies to auto&&
variables.
1. if T
is a template type, T&&
is a forwarding reference instead, in which case you use std::forward<T>(t)
instead of std::move(t)
the last time. See this question.
I found this article to be pretty enlightening on the subject of rvalue references in general. He mentions std::move
towards the end. This is probably the most relevant quote:
We need to use
std::move
, from<utility>
--std::move
is a way of saying, "ok, honest to God I know I have an lvalue, but I want it to be an rvalue."std::move
does not, in and of itself, move anything; it just turns an lvalue into an rvalue, so that you can invoke the move constructor.
Say you have a move constructor that looks like this:
MyClass::MyClass(MyClass&& other): myMember(other.myMember)
{
// Whatever else.
}
When you use the statement other.myMember
, the value that's returned is an lvalue. Thus the code uses the copy constructor to initialize this->myMember
. But since this is a move constructor, we know that other
is a temporary object, and therefore so are its members. So we really want to use the more-efficient move constructor to initialize this->myMember
. Using std::move
makes sure that the compiler treats other.myMember
like an rvalue reference and calls the move constructor, as you'd want it to:
MyClass::MyClass(MyClass&& other): myMember(std::move(other.myMember))
{
// Whatever else.
}
Just don't use std::move
on objects you need to keep around - move constructors are pretty much guaranteed to muck up any objects passed into them. That's why they're only used with temporaries.
Hope that helps!
When you have an object of type T&&
, a rvalue, it means that this object is safe to be moved, as no one else will depend on its internal state later.
As moving should never be more expensive than copying, you will almost always want to move it. And to move it, you have to use the std::move
function.
When should you avoid std::move
, even if it would be safe? I wouldn't use it in trivial examples, e.g.,:
int x = 0;
int y = std::move(x);
Beside that, I see no downsides. If it does not complicate the code, moving should be done whenever possible IMHO.
Another example, where you don't want to move are return values. The language guarantees that return values are (at least) moved, so you should not write
return std::move(x); // not recommended
(If you are lucky, return value optimization hits, which is even better than a move operation.)
You can use move when you need to "transfer" the content of an object somewhere else, without doing a copy. It's also possible for an object to take the content of a temporary object without doing a copy, with std::move.
Read more on Rvalue references and move constructors from wikipedia.