Die richtige Antwort hängt davon ab, über welchen C++ - Standard Sie sprechen.
Wenn wir über C++ 11 sprechen, ist das Klängen korrekt (eine explizite Verschiebung ist erforderlich). Wenn wir über C++ 14 sprechen, ist gcc korrekt (eine explizite Verschiebung ist nicht erforderlich).
C++ 11 sagt in N3290/[class.copy]/p32:
When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, ...
Dies erfordert, dass Sie nur die implizite Bewegung bekommen, wenn die Rückkehr Ausdruck den gleichen Typ wie die Funktion Rückgabetyp hat.
Aber CWG 1579 änderte dies, und dieser Fehlerbericht wurde nach C++ 11 und rechtzeitig für C++ 14 akzeptiert. Das gleiche Absatz lautet nun:
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return
statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, ...
Diese Modifikation erlaubt grundsätzlich die Rückkehr Ausdrucksart umwandelbar sein, um die Funktion Rückgabetyp und nach wie vor für die implizite Bewegung in Betracht.
Bedeutet dies, dass der Code eine #if
/#else
basierend auf dem Wert __cplusplus
braucht?
Man könnte das tun, aber ich würde nicht stören.Wenn ich zielte C++ 14, würde ich nur:
return i;
Wenn der Code unerwartet unter einem C++ 11-Compiler ausgeführt wird, werden Sie zum Zeitpunkt der Kompilierung des Fehlers mitgeteilt werden, und es ist trivial zu beheben:
return std::move(i);
Wenn Sie gerade Targeting 11 C++, die move
verwenden.
Wenn Sie sowohl C++ 11 als auch C++ 14 (und darüber hinaus) als Ziel verwenden möchten, verwenden Sie move
. Der Nachteil der Verwendung von move
ist, dass Sie RVO (Return Value Optimization) verhindern können. In diesem Fall ist RVO jedoch nicht einmal legal (wegen der Umwandlung von der return
-Anweisung in den Rückgabetyp der Funktion). Und so tut die kostenlose move
nichts weh.
Das ein Mal, wenn Sie zu einer unentgeltlichen move
auch anlehnen könnten, wenn C++ 14-Targeting ist, wenn ohne sie noch Dinge kompilieren in C++ 11 und rufen eine teure Kopie Umwandlung, wie zu einer Bewegung gegen Umwandlung. In diesem Fall würde das versehentliche Kompilieren unter C++ 11 einen stillen Leistungsfehler verursachen. Und wenn sie unter C++ 14 kompiliert wird, hat die kostenlose move
immer noch keine nachteiligen Auswirkungen.
Ich vermute, dass wir in der Lage sein werden, bessere Antworten zu geben, wenn wir verstehen, wofür Sie das brauchen. Im Moment könnte das trivial gelöst werden, indem make_shared statt make_unique aufgerufen wird. Ich nehme an, dass es einen Grund gibt, warum das nicht möglich ist, und es würde helfen, diesen Grund zu verstehen. – Elliott
@Eliott: Was könnte gelöst werden? Er fragt nicht, wie er etwas lösen soll, er fragt, ob der Code, den er hat, dem Standard entspricht. –