c++vectorreferencedynamic-arraysreturn-by-value

Returning Vectors standard in C++


Now, I know this is a common question, but I haven't been able to really find a straight answer on this. This is really a question about standards. I am working on a project involving the genetic algorithm. But I'm running into a bottleneck when it comes to returning a vector. Is there a "proper" way to do this. Normally I use dynamically allocated arrays, and return a pointer to a newly created array.

obj* func(obj* foo);

That way, everything is efficient and there is no copying of data. Is there an equivalent to doing this with a vector? This vector has objects in it, so returning it by value would be slow I imagine. Is the only solution to pass a "resultant" vector by reference?

void func(vector<obj> &input, vector<obj> &result);

And, on a side note for future reference, is it standard practice to use a vector or other STL container over a dynamically allocated array? Are dynamically allocated arrays only used as a low level tool for designing containers? Are they just a relic of the past?


Solution

  • vector<obj> func(const vector<obj>& input);
    

    All compilers implement RVO either by default or when you turn optimizations on, if you don't turn optimizations on you don't care about performance, so that would not be an issue anyway.

    If your compiler is C++11 conforming, then in the worst case instead of copying 1 pointer you will pay for 3 pointers when move semantics kick in, which compared with the cost of allocating the memory is really no cost.

    Build a simple meaningfull interface, then measure the performance and bottlenecks and optimize from there.

    Depending on your use pattern, if you can reuse the output container, you might want to transform the above into:

    void func(vector<obj>& output, const vector<obj>& input);
    

    This will have the same performance when creating a new vector, but if you call this function in a loop, you may be able to avoid a few allocations:

    std::vector<obj> output;
    for ( ... ) {
       output.clear();
       func(output, input);
    
    // compare with
    for ( ... ) {
       std::vector<obj> output = func(input);
    

    In the first block of code, if all of the vectors are of the same size, the clear() will remove the elements but leave the buffer intact, so that the next call to func need not allocate. In the second case it needs to allocate inside func and will deallocate at the end of the scope.

    This is a slightly uglier interface to use, so I would opt for the first one (which semantically is cleaner), and use the second only if the first proves to have an issue with multiple allocations.