views:

656

answers:

5

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?

+5  A: 

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.

sharptooth
Thanks for your reply.
Appu
A: 
  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!
}
Thomi
"you can return a const reference to a local temporary" no that's wrong. You cannot return a reference to a local or to temporaries created in that function. They will be destructed once the function returns, and the reference return value will refer to garbage. I think you had `const T` in mind, which is a different matter.
Johannes Schaub - litb
Yes, that is what I had in mind. I've made that more explicit now.
Thomi
+8  A: 

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.

Kirill V. Lyadvinsky
Is there any way in VS2008 to turn off all optimizations including RVO? I have turned off all but it is still doing RVO. This is just to understand the differences.
Appu
`/Od` should disable NRVO, but I'm not sure about RVO.
Kirill V. Lyadvinsky
Thanks. Let me try that
Appu
I'm pretty sure RVO is not applied to a debug build
Krugar
@Krugar: Well, it is applied. I am running a debug build.
Appu
MSVC applies RVO even if optimizations are disabled. It doesn't apply NRVO however.
jalf
How are you testing this? Please build the following code in both debug and release mode:#include <iostream> class myClass {public: myClass() {} myClass(const myClass } }; myClass foo() { myClass bar; return bar; } int main() { myClass baz = foo();}
Krugar
+2  A: 

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.

Krugar
However, I would prefer having that function as a void and return nothing as it processes the parameter. Return the reference parameter would just confuse other people when looking at the code.
Viktor Sehr
yes. It was just an illustrative example.
Krugar
+1  A: 

Since nobody mentioned it yet. I think this link is a good reading pertaining to your question.

t.g.