c++c++17copy-elisionnrvoreturn-by-value

best strategy for ensuring no copies in return by value


I'm using c++17, but I don't get to choose my compiler.

Suppose I have type S with move and copy semantics. Typically for me S will be a std::vector of some aggregate type. I'm also using a function g which returns an S by value:

S g(int x);

Suppose further I'm writing this function, f, with a single return statement: S f(int y) { ... return g(x);}

I have a choice for the final return:

(i) return g(x);
(ii) return S{g(x)};
(iii) S tmp = g(x); return tmp;

As I understand it, (ii) will guarantee copy elision, so the move construction of S from g will be constructed in the caller's memory. (iii) Is quite likely to guarantee NRVO, named return value optimisation, so tmp is move constructed, again in the caller's memory. But what can be said about (i)?

Which would you choose, given the need for good performance on any target? Or does it make no difference?


Solution

  • Use (i).

    (i) and (ii) are the same, both guarantee zero copies/moves since C++17.

    An extra constructor call in (ii) doesn't help at all, it's just one more thing to elide with the mandatory RVO.

    (iii) is worse: it guarantees a move at worst, or no move if the compiler performs NRVO (in which case it becomes the same as (i) and (ii)).