Обычно это не происходит из-за RVO .
Если эта оптимизация не может быть выполнена, то это будет ход, потому что возвращаемый объект выходит из области видимости (и будет уничтожен сразу после этого). Если его нельзя переместить, он будет скопирован. Если его нельзя скопировать, он не скомпилируется.
Весь смысл конструкторов перемещения заключается в том, что, когда копия будет сделана из объекта, который вот-вот должен быть уничтожен, часто нет необходимости делать целую копию, а ресурсы можно перемещать от умирающего объекта до создаваемого объекта.
Вы можете сказать, когда будет вызываться конструктор копирования или перемещения, основываясь на том, что должно произойти с перемещаемым / копируемым объектом. Это собирается выйти за рамки и быть разрушенным? Если это так, будет вызван конструктор перемещения. Если нет, то конструктор копирования.
Естественно, это означает, что вы можете иметь как конструктор перемещения, так и конструктор копирования в одном классе. Вы также можете иметь оператор присваивания копии и оператор присваивания .
Обновление: Может быть неясно, когда именно вызывается конструктор перемещения / оператор присваивания по сравнению с конструктором простого копирования / оператором присваивания. Если я правильно понимаю, конструктор перемещения вызывается, если объект инициализируется значением xvalue (значение eXpiring). §3.10.1 стандарта гласит
xvalue (значение «eXpiring») также относится к объекту, обычно рядом
конец его жизни (так что его ресурсы могут быть перемещены, для
пример). Xvalue является результатом некоторых видов выражений
включая ссылки на значения (8.3.2). [Пример: результат вызова
функция, тип возвращаемой которой является ссылкой на rvalue, является xvalue. -конец
пример]
И начало § 5 стандарта гласит:
[Примечание: выражение является xvalue, если оно:
- результат вызова
функция, неявно или явно, чей тип возвращаемого значения
rvalue ссылка на тип объекта,
- приведение к значению ссылки на
тип объекта,
- выражение доступа к элементу класса, обозначающее
нестатический член данных не ссылочного типа, в котором объект
Выражение является xvalue или
- a. * Выражение указателя на член в
который первый операнд является xvalue, а второй операнд является
указатель на элемент данных.
Как правило, эффект этого правила заключается в том, что
именованные ссылки на rvalue рассматриваются как lvalues, а неназванные rvalue
ссылки на объекты рассматриваются как значения x; Rvalue ссылки на
функции обрабатываются как l-значения, именованные или нет. —Конечная записка]
<ч />
Например, если 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);