Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is rvalue passed as parameter treated as lvalue inside the function?

Tags:

c++

c++11

rvalue

I have a View and a Shape class where the View "owns" its Shape objects. I am implementing this as a vector of unique_ptr. In the function View::add_shape(std::unique_ptr&& shape), I still need to use std::move on the rvalue parameter to make it compile. Why? ( using GCC 4.8 )

#include <memory>
#include <vector>
using namespace std;

class Shape { };
class View
{
  vector<unique_ptr<Shape>> m_shapes;
  public:
  void add_shape(unique_ptr<Shape>&& shape)
  { 
    m_shapes.push_back(std::move(shape));// won't compile without the std::move
  }
};


int main()
{
  unique_ptr<Shape> ups(new Shape);
  View v;
  v.add_shape(std::move(ups));
}
like image 487
user1057165 Avatar asked Sep 28 '13 03:09

user1057165


2 Answers

Yes, the rvalue reference from the parameter is only used to select the function from the caller's perspective, it behaves like an lvalue reference inside the function.

The reason is that you are only allowed to move a value once and it was deemed too dangerous to keep the rvalue-ness of a parameter automatically. The parameter type indicates that this function accepts an rvalue and makes potentially use of this by providing an implementation that actually moves the value. By overloading this version of the method can be used in favor of the non-moving version. Or it simply says that the function requires an rvalue.

What happens in the implementation of the function is another thing. Consider a method like

void add_shape_twice(unique_ptr<Shape>&& shape)
{ 
  m_shapes.push_back(shape);
  m_shapes.push_back(shape);
}

if shape as a parameter would remain an rvalue reference: You would have accidentally moved the value twice. Since in the real world functions may be longer and it's quite common to refer to the parameters multiple times (either explicitly or within a loop or pack expansion), the potential for errors would be enormous.

Even if we would all be aware of it and never forget about it, it would also mean that we need to cast away rvalue-ness and this would make the code quite clumsy. We would constantly be adding and removing rvalue-ness.

like image 195
Daniel Frey Avatar answered Nov 15 '22 04:11

Daniel Frey


Yes, after entering into the function that rvalue reference has a name now, so it's treat as lvalue. therefore you have to move it.

void add_shape(unique_ptr<Shape>&& shape)
                                   ^^^^^

Or pass it by value:

void add_shape(unique_ptr<Shape> shape)
like image 43
masoud Avatar answered Nov 15 '22 03:11

masoud