Search code examples
c++initializer-liststdinitializerlist

I need the option of passing in a vector of objects, or brace-enclosed list, to a constructor


My constructor originally took a std::vector<> but I couldn't figure out how to get a braced list to initialize it. I got it working after changing to an std:initializer_list<>. I found two ways: 1) passing the initializer_list in as a parameter to the array constructor (commented out in code below) and 2) using the std::copy algo (as seen in code below).

Now, I need to create this object with a std::vector<> and can't figure out how to convert it to the initializer_list. I could make a second constructor that takes a vector, but as an exercise I'd like to get this working with one constructor if possible.

Any ideas?

class One: public Base {
public:
  One( Two* ptwo_in, std::initializer_list<Three> ilthree ) :
    ptwo( ptwo_in )//,
    //athree_( ilthree )
  {
    athree_.reserve( ilthree .size() );
    std::copy( ilthree .begin(), ilthree .end(), athree_.begin() );
  }

  Two*               ptwo_;
  std::vector<Three> athree_;
};

  // Works fine:

  new One( &two, { Three( args ),
                   Three( args ),
                   Three( args ), } )



  // Doesn't work:

  std::vector<Three>* pathreeSomething
  athreeOther.push_back( new One( ptwoLocal, *pathreeSomething ) );

Solution

  • On that third line of code it works with replacing initializer_list with vector, true. But I don't want to pass around a whole vector as an arg.

    You're going to construct a vector anyway (One::athree_). So just move the vector passed to the constructor rather than copy it:

    class One: public Base {
    public:
        One(Two* ptwo_in, std::vector<Three> ilthree)
            : ptwo{ptwo_in}
            , athree_{std::move(ilthree)}
        { }
    
    private:    
        Two* ptwo_;
        std::vector<Three> athree_;
    };
    

    This is a common pattern in C++. Pass by non-const value and use move semantics to avoid copies:

    One one{some_ptr, {Three{args}, Three{args}, Three{args}}};
    

    or:

    std::vector<Three> vec{ ... };
    
    // moves 'vec' to the ctor parameter, the ctor then moves it to its member
    One one{some_ptr, std::move(vec)};
    

    No unnecessary copies that way.