Proper way (move semantics) to return a std::vector from function calling in C++11

20,199

Solution 1

If you're using a C++0x-compatible compiler and standard library, you get better performance from the first example without doing anything. The return value of get_vector(_n, _m) is a temporary, and the move constructor for std::vector (a constructor taking an rvalue reference) will automatically be called with no further work on your part.

In general, non-library writers won't need to use rvalue references directly; you'll just reap a decent chunk of the benefits automatically.

Solution 2

I believe (1) and (2) have identical performance even without C++0x, as long as your compiler does the Named Return Value Optimization, which I believe most do. Neither should do any copies, nor any moves.

Please correct me if I'm wrong, because if so I misunderstand NRVO.

Solution 3

In the particular case that you are considering, the first implementation is just as efficient as the second. The compiler will optimize the copy of ret in the get_vector function to the return value, and it will use move semantics to transfer ownership of the vector to the container class. Move construction in a vector requires (implementation dependent, but a good approximation is) 3 pointer copies, independently of the number and sizes of the elements in the container. Passing the vector as a reference to be modified requires a single pointer copy (approximate cost again), but any operation you perform on the vector will dominate the cost of either option.

There are some very specific circumstances when passing a vector into a function for modification might be faster, but those are rare and more related to the domain than to the vector itself. Just ignore that, code first for maintainability, and if the program is slow, profile, determine where the cost of the program is, and only then think on optimizing. The interesting part is that once you have profiled, you probably know what the bottleneck is and that means you will have hints into what to change.

Share:
20,199
Loom
Author by

Loom

Updated on October 12, 2020

Comments

  • Loom
    Loom over 3 years

    I want to fill std::vector (or some other STL container):

    class Foo {
    public:
      Foo(int _n, const Bar &_m);
    private:
      std::vector<Foo> fooes_;
    }
    

    1.Good looking ctor, expensive performance

    std::vector<Foo> get_vector(int _n, const Bar &_m) {
      std::vector<Foo> ret;
      ... // filling ret depending from arguments
      return ret;
    }
    
    Foo::Foo(int _n, const Bar &_m) : fooes_(get_vector(_n, _m) {}
    

    2. Better performance, worse looking ctor

    void fill_vector(int _n, const Bar &_m, std::vector<Foo> &_ret) {
      ... // filling ret depending from arguments
    }
    
    Foo::Foo(int _n, const Bar &_m) { fill_vector(_n, _m, fooes_); }
    

    Is it possible to rewrite get_vector function from 1st example with C++0x (move semantics features and so on) to avoid redundant copying and constructor calls?