Setting std :: vector in class constructor with different values ​​for element constructor

I have a class with a non-trivial constructor:

class mystream
{
public:
    mystream(size_t buffersize,size_t index) : buffersize(buffersize),index(index){}

    size_t buffersize;
    size_t index;
};

      

An instance mystream

has a unique identifier corresponding to its position in the vector of the controlling class:

class mystreammanager
{
public:
   mystreammanager() : streams(8,1024, /* WHAT TO DO HERE ??? */ )
   {
   }

  std::vector<mystream> streams;
};

      

How can I construct a vector and initialize its elements with ascending value for the index?

+3


source to share


5 answers


Concise, clear and easy to debug the way to do this is to defer vector construction to a static class function:

class mystreammanager
{
public:
   mystreammanager() : streams{ generate_streams(1024, 8) }
   {
   }

private:
  static std::vector<mystream> generate_streams(size_t buffersize, size_t qty)
  {
    std::vector<mystream> result;
    result.reserve(qty);
    for(size_t i = 0 ; i < qty ; ++qty) {
      result.emplace_back(buffersize, i); 
    }
    return result;
  } 

  std::vector<mystream> streams;
};

      



This is optimally effective because:

  • RVO calls vector creation in place
  • excluding list initialization means no redundant copies.
+8




Just use a loop:



mystreammanager() {
    streams.reserve(8);
    for (int i = 0; i < 8; ++i) {
        streams.emplace_back(1024, i);
    }
}

      

+3




Compile time version :)

Required c++14

, but can certainly be adapted forc++11

#include <cstddef>
#include <vector>
#include <utility>

class mystream
{
public:
  mystream(size_t buffersize,size_t index) : buffersize(buffersize),index(index){}

  size_t buffersize;
  size_t index;
};

template<size_t... Indexes>
std::initializer_list<mystream>    mystream_maker_impl(std::index_sequence<Indexes...>)
{
  return {{1024, Indexes}...};
}

template<size_t N>
std::initializer_list<mystream>    mystream_maker()
{
  return mystream_maker_impl(std::make_index_sequence<N>());
}

class mystreammanager
{
public:
  mystreammanager() : streams(mystream_maker<8>())
  {
  }

  std::vector<mystream> streams;
};

      

+3


source


You can do:

class mystreammanager
{
public:
   mystreammanager() : streams{{1024, 0}, {1024, 1}, {1024, 2}, {1024, 3},
                               {1024, 4}, {1024, 5}, {1024, 6}, {1024, 7}}
   {
   }

  std::vector<mystream> streams;
};

      

But doing the loop seems safer / easier.

+2


source


I used the answer from @RichardHodges as I was unhappy with my first choice. I came up with this pattern:

template<class T,class ...Args> std::vector<T> generate_with_index(size_t qty,Args ...args)
{
    std::vector<T> result;
    result.reserve(qty);
    for(size_t i = 0 ; i < qty ; ++qty)
        result.emplace_back(i, args...);
    return result;
}

      

This helps me avoid redundancy. From a theoretical point of view, I like @ Drax's solution better, as it works most efficiently at compile time.

+1


source







All Articles