63

Possible Duplicate:
What is move semantics?

I recently attended a C++11 seminar and the following tidbit of advice was given.

when you have && and you are unsure, you will almost always use std::move

Could any one explain to me why you should use std::move as opposed to some alternatives and some cases when you should not use std::move?

Marc.2377
  • 5,840
  • 5
  • 43
  • 75
pyCthon
  • 10,295
  • 16
  • 62
  • 122

4 Answers4

94

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.

Mooing Duck
  • 56,371
  • 16
  • 89
  • 146
  • ah ha! thats what i was looking for the universal reference case! – pyCthon Jan 23 '13 at 18:31
  • 7
    @pyCthon: for universal references you want to use `std::forward(t)` instead of `std::move(t)` the last time. – Mooing Duck Jan 23 '13 at 18:34
  • 5
    One thing to keep in mind that if you see a **named** variable then it doesn't matter if it is declared as `&&` ("rvalue") `&` (reference) or `` (copy) - it is always considered an **lvalue**. You can think of true rvalue references as temporary stuff that can be only returned from a function (your own, or wrapped in std::move() which - in the nutshell - returns the argument). – Red XIII Jan 23 '13 at 19:53
  • @LucDanton: I reworded, and added an additional sentence to clarify that the value category has little to do with the type. If it's still wrong, feel free to edit, or ping me a lecture in chat or something. – Mooing Duck Jan 23 '13 at 20:33
  • @MooingDuck : Would you mind elaborating (or posting a link) on the last part (std::forward vs std::move for universal references) ? – Macke Jan 30 '13 at 07:23
  • 1
    @Macke: With a universal reference you don't know if it's an rvalue or an lvalue, so you don't know if you need to `std::move` it or not. `std::forward` is the same as `std::move` if the input _was_ an rvalue, and does nothing if the input _was_ an lvalue, so you always get the correct mechanism. See [this question](http://stackoverflow.com/q/7257144/845092). – Mooing Duck Jan 30 '13 at 17:16
  • @MooingDuck: Ah. Got it. Thanks! :) – Macke Jan 30 '13 at 19:52
  • There is no such thing as a "universal reference", the only thing that exists is reference-collapsing rules. Might want to fix the answer. – user541686 Jan 13 '14 at 06:58
  • @Mehrdad I disagree, the use of reference collapsing rules is very commonly referred to as a "universal reference", in much the same way that dynamically allocated memory is said to come from "the heap". It's not "official terminology", but that's the common name for it. – Mooing Duck Jan 13 '14 at 18:00
  • Damn it, it seems that I am the only that couldn't get that "from a an object that was an rvalue", can you explain Psyduck? – gsamaras May 18 '15 at 14:30
  • 3
    @G.Samaras: rvalues are the unnamed results of expressions (functions and math operations).For instance, the result of `myintx + myinty` is itself an `int`,but has no name, so it would be an rvalue. You can pass this to a function expecting an rvalue (`&&`), but you could not pass it to a function expecing an lvalue reference (`&`). Likewise, you can't pass `myintx` to a function expecting an rvalue (`&&`) because it has a name. To "unname" an object, to tell the compiler it's safe to move that object, use the `std::move` function. – Mooing Duck May 18 '15 at 19:06
  • Thanks for clearly distinguishing between the two concepts: _type_ and _value category_; it's difficult to think about these things without knowing the proper terms. – legends2k Jun 26 '15 at 13:54
  • "The ``T&&`` merely means that ``t`` can be constructed from an object that was an rvalue". Isn't it that it *must* be constructed from an rvalue? (and ofc lvalues can be turned into rvalues e.g. via ``move``) – ben Mar 16 '17 at 10:28
  • @ben: fixed, thanks. – Mooing Duck Mar 16 '17 at 17:02
  • Also anything of the form auto&&, use std::forward instead of std::move. – novieq Nov 27 '17 at 09:15
  • @novieq: Added. – Mooing Duck Nov 27 '17 at 18:22
30

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!

Xavier Holt
  • 13,933
  • 3
  • 40
  • 56
4

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.)

Philipp Claßen
  • 32,622
  • 19
  • 125
  • 194
  • Scott Meyers argues that you should even move primitive types. – fredoverflow Jan 23 '13 at 18:35
  • @FredOverflow Interesting. Does he explain that in his C++ and Beyond 2012 talk? I can only think of using it as some kind of documentation but I'm not quite convinced that it is a good idea. – Philipp Claßen Jan 23 '13 at 18:39
  • 1
    He explains it in his talk I linked to as a comment to the question. He says "You should do this without even thinking about it". But just because Scott Meyers says it, doesn't mean it's the ultimate truth everybody has to adhere to without questioning it, of course. – fredoverflow Jan 23 '13 at 18:54
2

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.

Checkout this link

Eli Gassert
  • 9,338
  • 3
  • 24
  • 37
Rahul Tripathi
  • 152,732
  • 28
  • 233
  • 299