tags:

views:

195

answers:

6
+2  A: 

The first definitely does not copy the vector.

The cost of copying the vector could be linear in the number of elements in the vector.

The first introduces no risk of linear behavior on any platform or compiler, and no costs of profiling and refactoring.

Andy Thomas-Cramer
The first also allows to call several functions in a row to fill a single vector. If you need to do the same with #2, you'll have to copy elements from the vector being returned (which means that all the heroic RVO efforts by the compiler will be for nothing, since you'll end up with an immediately-discarded copy anyway).
Pavel Minaev
+5  A: 

One would assume parameter is best, but in practice it often is not. This depends on compiler. Some compilers (I think actually most recent compilers) will apply Return Value Optimization - Visual Studio 2005 and later should do it in both cases you have provided (see Named Return Value Optimization in Visual C++ 2005).

The best way to know for sure is to check the disassembly produced.

Suma
This is a _huge_ optimization, and most modern compilers leverage it with big gains in performance.
fbrereto
The whole idea of RVO makes me cringe. I hate it.
John Dibling
A: 

At a glance, the first two probably have more resizing of the vector going on, whereas the 3rd one probably does not need to resize the vector as it runs. This can be mitigated by resizing it yourself before the pushbacks.

Brian
+5  A: 

Adding a fourth variant into the mix:

void FillVector_4(vector<int>& v) {
   static const int tab[SZ] = {1,2,3, ... };
   v.assign(tab,tab+SZ);
}

If you're thinking about performance version 2 and version 3 may make the compiler create a vector<int> copy for the return value. That is, if the compiler isn't able to do NRVO (named return value optimization). Also, consecutive push_backs without a reserve probably leads to a couple of reallocations since the vector needs to grow. Whether this matters at all depends on your problem you're trying to solve.

You'll be pleased to know that C++0x will make returning a locally created vector very efficient. I also recommend reading David Abrahams article series about efficient value types including passing/returning.

sellibitze
+5  A: 

The biggest difference is that the first way appends to existing contents, whereas the other two fill an empty vector. :)

I think the keyword you are looking for is return value optimization, which should be rather common (with G++ you'll have to turn it off specifically to prevent it from being applied). That is, if the usage is like:

vector<int> vec = fill_vector();

then there might quite easily be no copies made (and the function is just easier to use).

If you are working with an existing vector

vector<int> vec;
while (something)
{
    vec = fill_vector();
    //do things
}

then using an out parameter would avoid creation of vectors in a loop and copying data around.

UncleBens
+1 for pointing out the difference between initialization and assignment w.r.t. copy elision.
sellibitze
+4  A: 

The idiomatic C++ approach would be to abstract over the container type by using an output iterator:

template<typename OutputIterator>
void FillContainer(OutputIterator it) {
    *it++ = 1;
    ...
}

Then it can be used with vector as:

std::vector<int> v;
FillContainer(std::back_inserter(v));

The performance (and other advantages, such as being able to fill a non-empty container) are the same as for your option #1. Another good thing is that this can be used to output in a streaming mode, where results are immediately processed and discarded without being stored, if the appropriate kind of iterator is used (e.g. ostream_iterator).

Pavel Minaev
+1. This seems like the most "STL way." Note that it might be useful to return the iterator from `FillContainer`.
Adrian McCarthy