views:

211

answers:

3

Is it possible to return a standard container from a function without making a copy?

Example code:

std::vector<A> MyFunc();

...

std::vector<A> b = MyFunc();

As far as I understand, this copies the return value into a new vector b. Does making the function return references or something like that allow avoiding the copy?

+7  A: 

If your compiler supports the NRVO then no copy will be made, provided certain conditions are met in the function returning the object. Thankfully, this was finally added in Visual C++ 2005 (v8.0) This can have a major +ve impact on perf if the container is large, obviously.

If your own compiler docs do not say whether or not it's supported, you should be able to compile the C++ code to assembler (in optimized/release mode) and check what's done using a simple sample function.

There's also an excellent broader discussion here

Steve Townsend
Thanks! Any idea about NRVO in gcc?
static_rtti
@static_rtti - I will have to defer to Linux folks for that one, for fear of putting foot in mouth
Steve Townsend
You can easily test with a class that traces in the Copy CTor. Note that this is a "can be" optimization, that won't necessarily work e.g. with differentrly named return objects. However, with C++0x rvalue references, classes can implement a guarantee. You can expect this for standard containers in an up-to-date STL.
peterchen
AFAIK, with GCC you'll have to turn this optimization off with -fno-elide-constructors, as it is otherwise enabled even with -O0.
UncleBens
@static_rtti: GCC is very good at eliding unnecessary copies. As far as I know, *no* other compiler is *better* at this -- just equally good or worse.
sellibitze
Agree with peterchen, there are a number of situations NRVO won't kick in, outlined in your linked document. I think the answer should discuss C++0x move semantics to deserve being the top-voted and chosen answer, so unfortunately I'm downvoting this. The compiler is never required to perform any optimization - with move semantics you can require the compiler not make a copy.
AshleysBrain
+2  A: 

If you can modify the signature of the function then you can use

std::vector<A>& MyFunc(); 

or

void MyFunc(std::vector<A>& vect);

You could also return a smart pointer, but that involves newing the object.

some_smart_pointer<std::vector<A>> MyFunc();

HTH

beezler
The first one is likely not going to work if you are returning a vector that's a local in the function. The second one is fine though
John Burton
+1 For the second form being the usual way to do this. The problem with the first example `std::vector<A>` is that the vector has to be allocated somewhere - `MyFunc` can't allocate it on the stack and return a reference. It is possible if the vector is a class member and you are just returning a reference to an existing vector.
Eclipse
@John Burton/@beezler - 'not going to work' is putting it mildly, assuming the returned container is stack-based in the called function.
Steve Townsend
@John Burton/@Steve Townsend: why exactly isn't it going to work?
static_rtti
@static_rtti: If the object is allocated on the stack, it will go out of scope when the function returns. So you're left holding a reference to an object that doesn't exist anymore.
Dennis Zickefoose
Because it will be "destructed" when the function ends so you'll be returning an reference to a variable that doesn't exist any more. Your compiler will likely warn you though at least
John Burton
+3  A: 

Rvalues ("temporaries") bound to const references will have their lifetime extended to the end of the reference's lifetime. So if you don't need to modify that vector, the following will do:

const std::vector<A>& b = MyFunc();

if you need to modify the vector, just code it the way that's easiest to read until your have proof (obtained through profiling) that this line even matters performance-wise.

Otherwise rely on C++1x with its rvalue references and move semantics coming along "real soon now" and optimizing that copy out without you having to do anything.

sbi