I want to return a large object from a function, for example, the variable std::string s; .
Do I need to write return std::move(s); ?

  • Okay, and when do I need to write std::move(x) ? - VladD
  • one
    @VladD is not in return but in y = move(x) or f(move(x)) . - Abyx
  • Understood thanks! I thought there is something more exotic. - VladD
  • one
    @Abyx I highly recommend to see Meyers, "Efficient and Modern C ++", in section 5.3 this issue is considered in detail. - Harry

2 answers 2

If the type of the variable coincides with the type of the return value, then do not write T t; return std::move(t); T t; return std::move(t); .

It is necessary to write T f() { T t; return t; } T f() { T t; return t; } T f() { T t; return t; } because in return variable t is considered rvalue.
The standard C ++ 11 says:

12.8 Copying and moving class objects [class.copy] p32

When the criteria for skipping copying / moving ( copy elision , including RVO) are met (except for restrictions on the parameters of the function), and the expression denoting the object to be copied is lvalue, then the constructor is selected as if it were rvalue.

One of the cases of copy skipping is NRVO :

In return , if the function returns a class *, and the return expression is the name of a non- volatile object with an automatic storage duration (except for the function parameter or catch ), and its type is the same as the return type.

(* note: struct and union are also types-classes )

In C ++ 14 , the wording is slightly different, the case of return considered separately from the copy skipping (RVO):

When the criteria for skipping copying / moving is met [...] and the expression in return is an lvalue or id-expression (including in brackets) that denotes an object with automatic storage duration declared in the body or parameters of a function or lambda expression .


Thus, starting from C ++ 11, the standard guarantees that if the optimizer is turned off, and NRVO is not, then in the following cases the displacement constructor will be called, not copied:

 struct T { T(); T(T&&); T(const T&); }; T f() { T t; return t; // Имя локальной переменной, вызов T::T(T&&) } T f() { T t; return (t); // Имя локальной переменной в скобках, вызов T::T(T&&) } T g(T t) { return t; // Имя параметра, вызов T::T(T&&) } 

Since all that std::move(x) does is to convert an expression into a reference to an rvalue, there is no point in writing T f() { T t; return move(t); } T f() { T t; return move(t); } T f() { T t; return move(t); } . (This also takes away the possibility of NRVO).

Moreover, if the expression in return not a name, then the automatic conversion to rvalue will not work.

 T f1() { struct X { T t; } x; return xt; // Часть объекта, будет вызов T::T(const T&) // Надо написать std::move(xt) } T g1(T* pt) { return *pt; // Не имя локальной переменной или параметра, // Надо написать std::move(*pt) } 

More complicated example:

 T h1() { T a; while (...) { T b; if (...) { return b; // вызов T::T(T&&) } } return a; // вызов T::T(T&&) } T h2(T a, T b, bool c) { return c ? a : b; // Не имя локальной переменной или параметра, // надо написать std::move(с ? a : b) } 

If the variable type differs from the return type , then the rules above do not work, and you should write std::move(t) :

 struct Base { virtual ~Base() {} }; struct Derived : Base {}; std::unique_ptr<Base> f() { std::unique_ptr<Derived> r; return std::move(r); // Нужен явный move, потому что типы разные. } 
  • By the way, the hose analyzer on such things swears. - Monah Tuk
  • Please explain in more detail what is meant by "is not a name." - Cerbo
  • About return (t) it would be necessary an explanation. Because An elementary check shows a call to a move constructor, not a copy. - αλεχολυτ
  • The phrase конструктор "перемещения" - это тоже конструктор копирования does not correspond to reality. A constructor cannot be both copying and moving. Accepts & means this is the copy constructor, if && , then this is already a motion constructor. - αλεχολυτ
  • @alexolut, thanks, corrected. The standard really distinguishes between copy and move constructors. - Abyx

Meyers in "Modern and Effective C ++" gives advice (Section 5.3, item 26 in the original) NOT to apply std::move() to local objects that can be optimized for the return value .

Roughly speaking, if it is the only object returned (that is, returned on all paths of execution), then it is not worth it. But if not - there may be different options.

  • Yes, it can be, but it may not be! What if NRVO doesn't work? Here is the MSDN page: msdn.microsoft.com/en-us/library/ms364057 ( v=vs.80 ).aspx says that there will be no NRVO if: Multiple return paths (even if the same named object is returned on all paths) with EH states introduced - sys_dev
  • @sys_dev For a long time to paint everything, there is not a single page of reasoning and consideration of different situations. I just gave a brief summary. I don’t know how it is in Russian, but the original is definitely on the net, so take a look .. - Harry
  • And who prevents you from doing the same as @Abyx? Create a question and answer it? And here is a link to this question - sys_dev
  • @sys_dev Frankly speaking, I am not so long on this resource, so while I look closely :) I didn’t even notice that the author of the question and answer is the same - this has never occurred to me :) But if you are talking about a big detailed answer - then, frankly, a lot and a long time to write - you need to have time and an appropriate mood, now neither one nor the other is enough ... - Harry
  • one
    Similar questions and answers you form a Russian-speaking programmer society! Someone from this society may well work side by side with you in the future. In other words, “you reap what you sow” - sys_dev