Переместить конструктор на производном объекте

Когда у вас есть производный объект с конструктором перемещения, а базовый объект также имеет семантику перемещения, каков правильный способ вызова конструктора перемещения базового объекта из конструктора перемещения производного объекта?

Сначала я попытался сделать самое очевидное:

 Derived(Derived&& rval) : Base(rval)
 { }

Однако, похоже, это вызывает вызов конструктора копии базового объекта. Затем я попытался явно использовать std::move здесь, например:

 Derived(Derived&& rval) : Base(std::move(rval))
 { }

Это сработало, но я смущен, почему это необходимо. Я думал, что std::move просто возвращает ссылку rvalue. Но так как в этом примере rval уже является ссылкой rvalue, вызов std::move должен быть лишним. Но если я не использую std::move здесь, он просто вызывает конструктор копирования. Итак, почему нужен вызов std::move?

Ответ 1

rval не является Rvalue. Это Lvalue внутри тела конструктора перемещения. Вот почему мы должны явно ссылаться на std:: move.

Обратитесь к этому. Важно отметить

Обратите внимание, что аргумент x равен рассматривается как внутреннее значение lvalue перемещать функции, даже если это объявлен как ссылка rvalue параметр. Вот почему это необходимо сказать move (x) вместо просто x, когда переходя к базовому классу. Эта является ключевой функцией безопасности перемещения семантика, предназначенная для предотвращения случайно двигаясь дважды с некоторых именованная переменная. Все перемещения происходят только из rvalues ​​или с явным литом rvalue, например, используя std:: move. Если у вас есть имя для переменной, это является lvalue.

Ответ 2

Вам действительно нужно использовать std:: forward (obj), а не std:: move (obj). Forward вернет правильное значение rvalue или lvalue, основанное на том, что obj, тогда как перемещение превратит lvalue в rvalue.