Ответ 1
Обычно это не будет из-за RVO.
Если эта оптимизация не может быть выполнена, то это будет движение, потому что возвращаемый объект выходит из области видимости (и будет уничтожен сразу после него). Если он не может быть перемещен, он будет скопирован. Если он не может быть скопирован, он не будет компилироваться.
Вся суть конструкторов перемещения заключается в том, что когда копия будет сделана из объекта, который вот-вот будет уничтожен, часто нет необходимости делать целую копию, и ресурсы могут быть перемещены из умирающего объекта к создаваемому объекту.
Вы можете указать, когда будет вызываться конструктор копирования или перемещения, основанный на том, что должно произойти с перемещаемым/скопированным объектом. Собираетесь ли вы выйти из сферы действия и быть разрушены? Если это так, вызывается конструктор перемещения. Если нет, конструктор копирования.
Естественно, это означает, что вы можете иметь как конструктор перемещения, так и конструктор копирования в том же классе. Вы также можете иметь оператор присваивания копии и оператор присваивания переадресации.
Обновление: Возможно, неясно, когда именно вызывается оператор конструктора перемещения/присваивания по сравнению с оператором конструктора/назначения простой копии. Если я правильно понимаю, конструктор перемещения вызывается, если объект инициализируется значением xvalue (значение eXpiring). В §3.10.1 стандарта говорится:
Значение xvalue (значение "eXpiring" ) также относится к объекту, обычно близкому конец его жизни (чтобы его ресурсы могли перемещаться, для пример). Значение x является результатом определенных видов выражений с использованием ссылок rvalue (8.3.2). [Пример: результат вызова функция, возвращающим тип которой является ссылкой rvalue, является значением x. -конец пример]
И в начале § 5 стандарта говорится:
[Примечание: выражение представляет собой значение x, если оно:
- результат вызова функции, неявно или явно, чей тип возврата является Ссылка на тип объекта,
- ссылка на ссылку rvalue для тип объекта,
- выражение доступа к члену класса, обозначающее нестатический элемент данных не ссылочного типа, в котором объект выражение является значением xvalue или
- a. * выражение "указатель-член" в который первым операндом является значение x, а второй операнд указатель на элемент данных.
В общем, эффект этого правила заключается в том, что Названные ссылки rvalue рассматриваются как lvalues и unnamed rvalue ссылки на объекты рассматриваются как xvalues; ссылки на функции обрабатываются как lvalues, именованные или нет. -end note]
В качестве примера, если NRVO можно сделать, он выглядит следующим образом:
void MoveAFoo(Foo* f) {
new (f) Foo;
}
Foo myfoo; // pretend this isn't default constructed
MoveAFoo(&myfoo);
Если NRVO не может быть выполнено, но Foo
является подвижным, тогда ваш пример немного выглядит следующим образом:
void MoveAFoo(Foo* fparam) {
Foo f;
new (fparam) Foo(std::move(f));
}
Foo f; // pretend this isn't being default constructed
MoveAFoo(&f);
И если он не может быть перемещен, но он может быть скопирован, то он вроде этого
void MoveAFoo(Foo* fparam) {
Foo f;
new (fparam) Foo((Foo&)f);
}
Foo f; // pretend this isn't default constructed
MoveAFoo(&f);