Prawidłowa odpowiedź zależy od standardu C++, o którym mówisz.
Jeśli mówimy o C++ 11, klang jest poprawny (wymagany jest wyraźny ruch). Jeśli mówimy o C++ 14, gcc jest poprawne (wyraźny ruch nie jest potrzebny).
C++ 11 mówi w 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, ...
Wymaga to, że można dostać tylko niejawny ruch powrotny, gdy wyrażenie ma ten sam typ jako typ zwracanej przez funkcję.
Ale zmieniono to CWG 1579, a ten raport o usterce został przyjęty po C++ 11, a w czasie dla C++ 14. Ten sam ustęp brzmi teraz:
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, ...
Modyfikacja ta pozwala w zasadzie rodzaj ekspresji powrót być zamienny do typ zwracanej przez funkcję i nadal kwalifikować się do utajonego ruchu.
Czy to oznacza, że kod wymaga #if
/#else
w oparciu o wartość __cplusplus
?
Można to zrobić, ale nie zawracałbym sobie głowy.Gdybym kierowania C++ 14, ja po prostu:
return i;
Jeśli kod jest nieoczekiwanie pracował w C++ 11 kompilatora, użytkownik zostanie powiadomiony w czasie kompilacji błędu, a to jest trywialne naprawić:
return std::move(i);
Jeśli dopiero kierowania C++ 11, użyj move
.
Jeśli chcesz kierować zarówno C++ 11, jak i C++ 14 (i nie tylko), użyj move
. Wadą korzystania z usługi move
jest nieuzasadniona możliwość zablokowania RVO (Optymalizacja wartości zwracanej). Jednak w tym przypadku RVO nie jest nawet legalne (z powodu konwersji z instrukcji return
na typ zwracany przez funkcję). I tak darmowy move
nic nie boli.
Ten czas można pochylić w kierunku nieodpłatnego move
nawet podczas kierowania C++ 14 jest czy bez niego, sytuacja wciąż kompilacji w C++ 11 i powołać drogiego kopia konwersji, w przeciwieństwie do ruchu Konwersja. W tym przypadku przypadkowe skompilowanie pod C++ 11 wprowadziłoby cichy błąd wydajności. A gdy kompilowany pod C++ 14 darmowy move
nadal nie ma szkodliwych skutków.
Podejrzewam, że będziemy w stanie udzielić lepszych odpowiedzi, gdy zrozumiemy, czego potrzebujesz. W tej chwili można to rozwiązać banalnie, wywołując make_shared zamiast make_unique. Zakładam, że jest jakiś powód, dla którego nie jest to możliwe i pomoże to zrozumieć. – Elliott
@ Elliott: Co można rozwiązać? Nie pyta, jak rozwiązać cokolwiek, pyta, czy kod, który ma, jest poprawny według standardu. –