问题
When I want a function to return me a container:
vector<T> func(){
vector<T> result;
...
return result;
}
To be used in the following way:
vector<T> result = func();
In order to avoid the overhead of copying my container I often write the function so that it returns nothing but accept a non-const instance of the container.
void func(vector<T>& result){
result.clear();
...
result;
}
To be used in the following way:
vector<T> result;
func(result);
Is my effort meaningless because I can be sure that the compiler always uses the return value optimization?
回答1:
It is meaningless. The type of RVO you mentioned is called named RVO (NRVO), and most compilers implement it.
Regardless, in C++11, vector
has move constructors, so even if NRVO didn't apply, it'd still be moved, not copied.
回答2:
RVO is not guaranteed but decent compilers will use it when permitted.
However the problem is RVO only helps when you are creating a new object outside the function. If you reuse the same vector by passing it by reference, you can take advantage of its reserved capacity to reduce the number of memory allocations. A local vector created inside the function will always need to allocate a new buffer internally, no matter where the return value is stored. Therefore it can be more efficient to pass the vector by reference, even though the code looks less nice.
回答3:
Depends on age of your compiler. Before C++11, your alternative approach is what is needed unless the compiler supports named return value optimisation - which not all older compilers do. Also, you could also have the function return a reference to the passed vector.
From C++11, the language supports move construction, and the standard containers have working move constructors, so your first approach is fine. Purists will insist that is better. Pragmatists (who realise that not everyone can update their compilers without a huge impost) will say to pick a solution depending on whether your code needs to continue working with a mix of pre-C++11 and later compilers.
回答4:
I've tried it with gcc. I realized that I cannot rely on NRVO when compiling without C++11 flags.
Since I don't like the second signature (where the function takes the container by reference) I came out with this:
Declare the function in its natural form:
vector<T> func(){
vector<T> result;
...
return result;
}
and, when I am not sure about the compiler and the compilation flags, use it in this way:
vector<T> result;
func().swap(result)
in this way one gets the wanted interface and is sure to avoid elidible overheads.
Notice that the capacity of the result
vector is the one of the vector returned by the function. If one wants to set the capacity for the vector, the right interface for the function is the second one.
来源:https://stackoverflow.com/questions/33562810/return-value-optimization-ho-can-i-avoid-copy-construction-of-huge-stl-containe