1

I ran into some code in our project like this:

class A {
public:
  A(A&& obj): valid_(false), data_(obj.data_) {}
  //...
  void print() {
    for (auto x : data_) cout<<x<<" ";
    cout<<endl;
  }
private:
  bool valid_;
  vector<int> data_;
};

Is this a valid implementation of move constructor? Is it a must to use std::move() for member variables in move constructor in this case?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Deqing
  • 14,098
  • 15
  • 84
  • 131

2 Answers2

4

It is important to remember that "lvalue" and "rvalue", and the zoo of other "*values" apply not to variables, but to expressions.

The expression obj.data_ is an lvalue expression, and the easiest way to see this is to consider that &obj.data_ is well formed, whereas taking the address of an rvalue expression is not.

To allow move semantics to apply, you must take the result of this lvalue expression and cast it via std::move so that it is an rvalue expression to which move semantics (for whatever type data_ happens to be) actually apply.

Therefore, yes, you must apply std::move.

acm
  • 12,183
  • 5
  • 39
  • 68
2

You would need to change data_(obj.data_) to data_(std::move(obj.data_)) or it will be copy constructed; named variables are never r-value references unless explicitly moved (or forwarded under appropriate conditions); C++ won't implicitly apply move transitively to object attributes.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271