Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to return a std::vector in c++

People also ask

Can you return a vector?

Yes, a function can return a vector in C++ and in different ways. This article explains the different ways in which a C++ function can return a vector. In order to code a vector in C++, the vector library has to be included in the program.

How do you return a vector by reference?

vector<SalesItem> *getSalesItems(); returns a pointer and does not return a reference. void Invoice::getSalesItems() doesn't return anything. The function definition in the class and the declaration must be the same: vector<SalesItem> & getSalesItems(); returns a vector by refernece.

How do you return a vector at the end in C++?

back(). c; is what you want. end() returns the iterator (not an element) past-the-end of the vector. back() returns a reference to the last element.


In C++11, this is the preferred way:

std::vector<X> f();

That is, return by value.

With C++11, std::vector has move-semantics, which means the local vector declared in your function will be moved on return and in some cases even the move can be elided by the compiler.


You should return by value.

The standard has a specific feature to improve the efficiency of returning by value. It's called "copy elision", and more specifically in this case the "named return value optimization (NRVO)".

Compilers don't have to implement it, but then again compilers don't have to implement function inlining (or perform any optimization at all). But the performance of the standard libraries can be pretty poor if compilers don't optimize, and all serious compilers implement inlining and NRVO (and other optimizations).

When NRVO is applied, there will be no copying in the following code:

std::vector<int> f() {
    std::vector<int> result;
    ... populate the vector ...
    return result;
}

std::vector<int> myvec = f();

But the user might want to do this:

std::vector<int> myvec;
... some time later ...
myvec = f();

Copy elision does not prevent a copy here because it's an assignment rather than an initialization. However, you should still return by value. In C++11, the assignment is optimized by something different, called "move semantics". In C++03, the above code does cause a copy, and although in theory an optimizer might be able to avoid it, in practice its too difficult. So instead of myvec = f(), in C++03 you should write this:

std::vector<int> myvec;
... some time later ...
f().swap(myvec);

There is another option, which is to offer a more flexible interface to the user:

template <typename OutputIterator> void f(OutputIterator it) {
    ... write elements to the iterator like this ...
    *it++ = 0;
    *it++ = 1;
}

You can then also support the existing vector-based interface on top of that:

std::vector<int> f() {
    std::vector<int> result;
    f(std::back_inserter(result));
    return result;
}

This might be less efficient than your existing code, if your existing code uses reserve() in a way more complex than just a fixed amount up front. But if your existing code basically calls push_back on the vector repeatedly, then this template-based code ought to be as good.


It's time I post an answer about RVO, me too...

If you return an object by value, the compiler often optimizes this so it doesn't get constructed twice, since it's superfluous to construct it in the function as a temporary and then copy it. This is called return value optimization: the created object will be moved instead of being copied.


A common pre-C++11 idiom is to pass a reference to the object being filled.

Then there is no copying of the vector.

void f( std::vector & result )
{
  /*
    Insert elements into result
  */
} 

If the compiler supports Named Return Value Optimization (http://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx), you can directly return the vector provide that there is no:

  1. Different paths returning different named objects
  2. Multiple return paths (even if the same named object is returned on all paths) with EH states introduced.
  3. The named object returned is referenced in an inline asm block.

NRVO optimizes out the redundant copy constructor and destructor calls and thus improves overall performance.

There should be no real diff in your example.