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.