4

So I just got really surprised to find that in this code:

void AddLayer( shared_Layer_ptr && pNewLayer_p ){

        m_layers.push_back( pNewLayer_p ); // *
    }

The push_back being called is the "& param", not the "&& param" version. m_layers is a std::vector. Since pNewLayer_p is a "&&", I though it was a damn rvalue..The only way I manage to get the push_back("&& param") called is by using std::move:

m_layers.push_back( std::move(pNewLayer_p) );

To me seems redundant since pNewLayer_p is already a "&&".. Im sure missing something, what is it?

Icebone1000
  • 1,231
  • 4
  • 13
  • 25

2 Answers2

2

pNewLayer_p is an rvalue reference, but it is not an rvalue itself – basically because it has a name. Rvalues are defined as follows in the Standard:

(3.10/1) An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

In other words, rvalues are literals, temporaries and otherwise unnamed objects (such as xvalues, i.e. values that have just been returned by a function, but not been assigned to anything yet).

The rvalue reference pNewLayer_p in your code is a named object, so it is itself an lvalue. Applying std::move to it, which is formally a function, turns it (formally) into something returned from a function, i.e. an xvalue, which is an rvalue that you can pass to the move-version of push_back. This is what std::move exists for.

(Note: The above assumes that shared_Layer_ptr is a type, not a template parameter. If it is a template parameter, shared_Layer_ptr && would be a so-called universal reference, i.e. it may be an lvalue reference or an rvalue reference depending on how the template is instantiated. In this case, std::forward would be the appropriate function to use instead of std::move.)

jogojapan
  • 68,383
  • 11
  • 101
  • 131
  • does it worth to use std::move in this case? Will it avoid a copy on the push_back or it depends entirely on the type (in this case a shared ptr) move assignment overload? (I cant really understand the messy implementation on visual studio) – Icebone1000 May 29 '13 at 01:14
  • 1
    @Icebone1000 If you use `std::move`, it will call the move-constructor of `shared_Layer_ptr` to put it into the vector. If you don't use `std::move`, it will use the copy constructor instead. If `shared_Layer_ptr` works in a way similar to `std::shared_ptr`, the move method can be expected to be considerably faster, since no reference counts etc. will have to be updated. (Note that there may be a third method, using `emplace_back` instead of `push_back`. This can only be used if `pNewLayer_p` is an object that is newly created when the function is called. – jogojapan May 29 '13 at 01:22
  • 1
    @Icebone1000 (..cont'd) `emplace_back` takes the arguments of the constructor call for a new `shared_Layer_ptr`, rather than the constructed object itself. It then constructs it right inside the vector. This is the fastest possible, but it only works for newly created objects. If the objects are pre-existing and you want to move them in, use the `std::move` method. – jogojapan May 29 '13 at 01:23
  • thanks man! shared_Layer_ptr is really a std::shared_ptr typedef. I feel a urge to put std::move all over my code – Icebone1000 May 29 '13 at 01:29
  • @Icebone1000 Yes, in situations like the above I think it should help. Make sure you measure times if you want to be really sure. Related question: http://stackoverflow.com/questions/10953325/should-i-stdmove-a-shared-ptr-in-a-move-constructor – jogojapan May 29 '13 at 01:40
2

Think what will happen if it moves pNewLayer.

void AddLayer( shared_Layer_ptr && pNewLayer_p ){
    m_layers.push_back( pNewLayer_p );
    // what if pNewLayer_p is already moved
    another_m_layers.push_back( pNewLayer_p );
}

Therefore you must use std::move explicitly:

void AddLayer( shared_Layer_ptr && pNewLayer_p ){
    m_layers.push_back( pNewLayer_p );
    another_m_layers.push_back( std::move(pNewLayer_p) );
}

If an rvalue reference can only appear once in a function, that will definitely remove some power from C++.

Jiaming Lu
  • 875
  • 6
  • 20