Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why move constructor of member variable is not called?

Consider the following classes. If I implement the move constructor myself as follow, why bar member b is not moved but copied? But if I use the default move constructor, then b is moved. Why b(rhs.b) doesn't call bar(bar&&) ?

I use g++ 9.2.1 with --std=c++11.

class bar {
public:
    bar() { cout << "bar constructor" << endl; }
    bar(const bar& rhs) { cout << "bar copy constructor" << endl; }
    bar(bar&& rhs) { cout << "bar move constructor" << endl; }
};

class foo {
    bar b;
public:
    foo() { cout << "foo constructor" << endl; }
    foo(const foo& rhs) { cout << "foo copy constructor" << endl; }
    // foo(foo&& rhs) = default;
    foo(foo&& rhs) : b(rhs.b) { cout << "foo move constructor" << endl; } // my version
    //               ^^^^^^^^
};

foo f;
foo g = std::move(f);
like image 247
Gary Avatar asked Apr 10 '26 03:04

Gary


1 Answers

Why b(rhs.b) doesn't call bar(bar&&) ?

Because rhs.b is an lvalue, and rvalue references don't bind to lvalues. As a result – and because lvalue references do bind to lvaluesthe overload bar(const bar&), i.e., the copy constructor, is selected instead of bar(bar&&).

In order to get the move constructor selected, you need to mark rhs.b as "available for moving" with (<utility>) std::move() when initializing foo's b member:

foo(foo&& rhs): b(std::move(rhs.b)) { /* ... */ }
                  ^^^^^^^^^

This is a cast that turns the expression rhs.b into an xvalue, i.e., an rvalue, which binds to an rvalue reference. So, the move constructor is selected this time.

But if I use the default move constructor, then b is moved.

The default move constructor performs a member-wise move.

like image 191
ネロク・ゴ Avatar answered Apr 12 '26 17:04

ネロク・ゴ



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!