What's happening:
On the callerโs side, a return slot is provided that can hold the result, which means that the caller provides memory for a variable of type std::vector<int> . He expects the called method to build the value and is responsible for calling the destructor when the result is no longer in use and frees memory (if necessary, it probably just lives on the stack).
The called function (which can live in another translation unit!) Will be without NRVO, so this is:
- Provide a memory slot for
ret . - Build the local variable
ret in this memory slot. - Make stuff ...
- Copy-build the return value in the provided memory slot by copying
ret . - Call
ret destructor.
Now, with NRVO, the decision to optimize this can be made in the translation block of the called function . It converts the above value to:
- Build a
ret in the memory of the method return slot. - Make stuff ...
There is no need to do anything, since the memory belongs and the destructor is called by the caller, and because the optimization is transparent to the caller :)
This, of course, cannot eliminate the assignment in v in your example. If you save the result in another variable, for example
std::vector<int> w = f(v);
NRVO will build ret directly into w memory (since it will be passed as a backward slot to f ).
Daniel Frey
source share