3

In my textbook, the implementation of the vector push_back move implementation is:

void push_back( Object && x )
{
    if( theSize == theCapacity )
        reserve( 2 * theCapacity + 1 );
    objects[ theSize++ ] = std::move( x );
}

My understanding of std::move is that it basically static casts the item as an rvalue reference. So why on the last line did they have to use std::move( x ), when x was passed in already as an rvalue reference?

Stfyou
  • 33
  • 4
  • The expression `x` in this scope is not an rvalue, it's an lvalue that happens to have the *type* reference to rvalue (or lvalue depending on the type of `Object` if it's a template parameter). lvalues won't bind to rvalue references so the move assignment won't be called without `std::move`. – user657267 Oct 19 '15 at 02:32
  • @user657267 I don't understand, how is it advantageous to overload a function with a rvalue reference parameter, if the thing being passed in is just an lvalue that happens to have the type reference to rvalue. – Stfyou Oct 19 '15 at 02:44
  • Because `objects[ theSize++ ] = x;` will call `Object& operator=(Object const&)`, not `Object& operator=(Object &&)`. Like I said lvalues don't bind to rvalue references, it doesn't matter what their type is. The expression `x` is an lvalue, the expression `std::move(x)` is an rvalue. I get the feeling your confusing the *value category* of an expression with its *type*. – user657267 Oct 19 '15 at 02:47
  • @user657267 So, for example, if I were pushing back an int, then I would call vec.push_back(1); In this case, 1 is an rvalue, right? So then does 1 get binded to the lvalue x, which is why when I want to use move semantics on the last line, then I would have to statically cast x back as an rvalue using std::move? – Stfyou Oct 19 '15 at 02:57
  • That's one way to put it, the legalese description would be: overload resolution selects `push_back(Object &&)` -> the rvalue expression `1` is used to initialize the variable `x` -> the lvalue expression `x` is used to initialize `std::move`'s variable `t` -> overload resolution selects `Object& operator=(Object &&)` -> the rvalue expression `std::move( x )` is used to initialize whatever the name of the variable in the assignment operator is. – user657267 Oct 19 '15 at 04:19

1 Answers1

2

x is an rvalue reference, but the rule of thumb you must follow is: if it has a name, it's an lvalue. Therefore you must apply std::move to convert its type to an rvalue. If you left out the std::move then x would be copied instead of moved into its destination. More information can be found in Rvalue References Explained.

David G
  • 94,763
  • 41
  • 167
  • 253