Return values and RVO
When we are returning an object from a function by value, actually the compiler should construct a temporary object, fill inside of the function, return it to the caller, and then use assignment to copy the contents of the temporary object into the result object. Pretty inefficient, huh?
Because of that, very early on compilers implemented a simple optimization allowing the called function to fill the result object directly, skipping the unneeded creation of a temporary. There are two cases of that optimization, simple return value optimization (RVO), when we return an unnamed object, and named return value optimization (NRVO), when, true to its name, we return a named object:
T func1()
{
...
return T(); // RVO
}
T func2()
{
T t;
...
return t; // NRVO
}
C++89 compilers normally used to implement NRVO, but could sometimes become confused whether a function could return an object from two or more different control paths. The standard itself stated that these optimizations were optional, so you couldn't bet on that.
Another place where RVO couldn't be applied was in cases of the chaining of operators, as shown in the following example:
std::string s1, s2, s3, s4;
...
s1 = s2 + s3 + s4;
The addition on the left side would create two temporary objects (each for one addition) and then assign it to the destination object. The usual workaround was the following ugly one:
s1 += s2;
s1 += s3;
si += s4;