Understanding return value optimization and returning temporaries - C++

Please consider the three functions.

std::string get_a_string()
{
    return "hello";
}

std::string get_a_string1()
{
    return std::string("hello");
}

std::string get_a_string2()
{
    std::string str("hello");
    return str;
}
  1. Will RVO be applied in all the three cases?
  2. Is it OK to return a temporary like in the above code? I believe it is OK since I am returning it by value rather than returning any reference to it.

Any thoughts?


Solution 1:

In two first cases RVO optimization will take place. RVO is old feature and most compilers supports it. The last case is so called NRVO (Named RVO). That's relatively new feature of C++. Standard allows, but doesn't require implementation of NRVO (as well as RVO), but some compilers supports it.

You could read more about RVO in Item 20 of Scott Meyers book More Effective C++. 35 New Ways to Improve Your Programs and Designs.

Here is a good article about NRVO in Visual C++ 2005.

Solution 2:

First, it's completely okay to return a temporary by value which is what you do. It is copied and though the original will go out of scope the copy will not do so and can be safely used by the caller.

Second, all three cases are in fact identical (since you don't access the temporary in the third case anyway) and a compiler might even emit the same code for all of them. Hence it can use RVO in all three cases. This is entirely compiler-dependent.

Solution 3:

All cases are correct. They all will construct a temporary and apply the copy constructor of the return type. Necessarily, if there is no copy constructor, the code will fail.

RVO will happen on all three cases under most compilers. Only difference is the last one where the standard does not force it. This because you have a named variable. But most compilers are smart enough to apply RVO to it still... the later the named variable is declared and the less transformations it is applied to, the better odds for RVO to be applied to a named variable.

Incidentally, returning a reference is of course possible as you might have seen in other code. What you must not do is return a reference t a local object.

std::string& get_a_string2()
{
    std::string str("hello");
    return str; //error!
}

Will produce a compile time error, as you know. However,

std::string& get_a_string2(std::string& str)
{
    // do something to str
    return str; //OK
}

Will work just fine. On this case, there's no construction or copy construction involved. Simply the function returns a reference to its argument.

Solution 4:

  1. It depends on your compiler - what platform are you referring to? Best way to find out is to compile a very small test app and check the ASM your compiler produces.

  2. Yes, it is OK, although you never mention what you're concerned about; speed? style? you can a local temporary to a const reference - the lifetime of the temporary will be extended to the lifetime of the reference - try it and see for yourself! (Herb Sutter exaplins this here) See end of post for example.

IMO you're almost always better off trusting your compiler to optimise your code for you. There are very few cases where you should need to care about this sort of thing (very low level code is one such area, where you're interactive with hardware registers).

int foo() { return 42; }

int main(int, char**)
{
    const int &iRef = foo();
    // iRef is valid at this point too!
}