Почему не вызывается конструктор перемещения переменной-члена?

Рассмотрим следующие классы. Если я реализую конструктор перемещения самостоятельно, как показано ниже, почему элемент панели b не перемещается, а копируется? Но если я использую конструктор перемещения по умолчанию, то b перемещается. Почему b(rhs.b) не звонит bar(bar&&)?

Я использую g++ 9.2.1 с --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);

person Gary    schedule 14.10.2020    source источник


Ответы (1)


Почему b(rhs.b) не звонит bar(bar&&) ?

Поскольку rhs.b является lvalue, а ссылки на rvalue не связаны с lvalues. В результате — и поскольку ссылки lvalue действительно связаны с lvaluesвыбирается перегрузка bar(const bar&), т. е. копирующий конструктор вместо bar(bar&&).

Чтобы выбрать конструктор перемещения, вам нужно пометить rhs.b как доступный для перемещения с помощью (<utility>) std::move() при инициализации члена b foo:

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

Это приведение, которое превращает выражение rhs.b в xvalue, т. е. rvalue, которое привязывается к ссылке rvalue. Итак, на этот раз выбран конструктор перемещения.

Но если я использую конструктор перемещения по умолчанию, то b перемещается.

Конструктор перемещения по умолчанию выполняет перемещение по элементам.

person 眠りネロク    schedule 14.10.2020