Почему явный вызов базового конструктора перемещения фактически вызывает базовый конструктор копирования? [дубликат]


На этот вопрос уже есть ответ здесь:

Я пытаюсь позвонить прямо на базу переместить конструктор класса через производный двигаться конструктор класса а, сюрприз!, что на самом деле вызывает базовый конструктор копирования класса не основание двигаться конструктор класса.

Я использую функцию std::move() на объекте, чтобы быть уверенным что производные двигаться конструктор вызывается!

Код:

class Base
{
public:
    Base(const Base& rhs){ cout << "base copy ctor" << endl; }
    Base(Base&& rhs){ cout << "base move ctor" << endl; }
};

class Derived : public Base
{
public:

    Derived(Derived&& rhs) : Base(rhs) { cout << "derived move ctor"; }
    Derived(const Derived& rhs) : Base(rhs) { cout << "derived copy ctor" << endl; }
};

int main()
{
    Derived a;
    Derived y = std::move(a); // invoke move ctor
    cin.ignore();
    return 0;
}

ВЫВОД ПРОГРАММЫ:

Базовая копия ctor

Производный ход ctor

Как вы видите, базовый класс move ctor забывается, так как же его назвать?

3 3

3 ответа:

В контексте вашего класса Derived параметр rhs явно имеет имя. Таким образом, это должно быть lvalue, это не может быть rvalue. Однако T&& связывается только с rvalues. Если вы хотите вызвать конструктор перемещения базового класса, вам нужно использовать следующий код:

Derived(Derived&& rhs): Base(std::move(rhs)) { std::cout << "derived move ctor"; }

Это вызовет конструктор перемещения Base и переместит Base Часть rhs. Поскольку Base ничего не знает о членах Derived, конструктор Base move не будет перемещать ничего, добавленное Derived.

Конструктор или любая другая функция или метод, имеющие && в сигнатуре, могут быть выбраны компилятором только в том случае, если выполняются оба эти условия:

  • Тип данных выражения, которое вы передаете, - T&& или T. - то есть T& не будет принято
  • и фактически это должно быть rvalue - например, возвращаемое (по значению T или по T&&) из функции.

move(rhs) удовлетворяет обоим этим условиям. rhs имеет право тип, но он фактически должен быть возвращен из функции (например, move), прежде чем его можно будет считать допустимым для передачи в функцию, которая требует &&.

Если используется конструктор перемещения базового класса, то производный конструктор может получить доступ к объекту перемещения из. Это опасно, поэтому это не произойдет, если вы явно не скажете компилятору, что вы закончили использовать объект и его безопасно перемещать.