简体   繁体   中英

Initialize vectors size in array of objects

I want to initialize the sizes of vectors in an array of objects.

Every vector have the same size so...

LIB FILE:

#include <vector>

Class NameClass
{
 public:
  explicit NameClass( unsigned size )
  {
    vectorName.resize( size );
  }

  std::vector <type> vectorName;
};

MAIN FILE:

#include "lib.hpp"

int main( void )
{
  NameClass object( size ); #1

  NameClass object[ number_objects ]( size ); #2
  NameClass object[ number_objects ] = {NameClass(size), NameClass(size), ... }; #3

  return 0;
}

The #1 works, but is not an array, The #2 doesn't, compiler says "conversion from int to non-scalar type 'NameClass' requested" And #3 works, but... it's just absurd initialize every object. and I can't just put a static to size inside the class, because the value change.

So... My research say that I need use std::generate. the question is... Whats is the best way?

Sorry if is easy question how to use std::generate I'm beginner and get troubles to find the optimal solution.

Some people suggest complex solutions but, I keep using my solution

#include "lib.hpp"

int main( void )
{
  unsigned number_objects = something;
  unsigned size = other_thing;
  NameClass object[ number_objects ];

  for( unsigned i = 0; i < number_objects; i++)
    object[i].vectorName.resize( size );

  return 0;
}

I use thins because is really easy to understand , and works . But I'm open to other easy to understand and functional solutions.

link std::generate

If you are willing to use std::array and C++14, we get:

template<std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
  return [](auto&&f)->decltype(auto) {
    return decltype(f)(f)(std::integral_constant<std::size_t, Is>{}...);
  };
}
template<std::size_t N>
auto index_upto( std::integral_constant<std::size_t, N> ={} ) {
  return index_over( std::make_index_sequence<N>{} );
}

template<std::size_t N, class F,
  class T = std::decay_t<std::result_of_t< F&( std::integral_constant<std::size_t, 0>& )>>,
  class R = std::array<T, N>
>
R make_array( F&& f ) {
  return index_upto<N>()( [&](auto...Is)->R {
    return {{ f( Is )... }};
  } );
}

we pass make_array<count> a lambda. That lambda takes an argument convertible-from a compile-time std::size_t whose value is I, and returns the Ith element of the array.

The result is a std::array of size count .

The lambda could take an auto I to get the compile-time juiciness, or just std::size_t I to get a runtime version of the value.

Most of the above can be translated into C++11, it just gets ugly. And I don't like ugly code.

Live example .

Your code would look like:

int main( void )
{
  unsigned size = 17;
  constexpr std::size_t number_objects = 3;

  auto objects = make_array<number_objects>( [&](std::size_t){ return NameClass(size); } );
}

and objects is now a ( std:: ) array of NameClass of length number_objects , all of size size .

Create a default constructor for your class:

#include <vector>

class NameClass {
 public:
 NameClass() {} // default constructor

 explicit NameClass( unsigned size ){
    vectorName.resize( size );
 }
 std::vector <type> vectorName;
};

In main:

#include "lib.hpp"

int main( void )
{
  unsigned number_objects = something;
  unsigned size = other_thing;
  NameClass object[ number_objects ];

  for( unsigned i = 0; i < number_objects; i++)
    object[i].vectorName.resize( size );

  return 0;
}

The reason example 2 wasn't working is because C++ does not have a syntax for creating an array of objects for which a default constructor is not provided.

In python it would look something like:

[NameClass(size) for _ in range(number_objects)]

I digress.

To do without the default constructor and still create a list of, you can use this (question is why you would want to do this):

#include <iostream>

static constexpr unsigned NUM_OBJECTS = 10;
static constexpr unsigned VEC_SIZE = 30;

int main() {
    NameClass *objects = static_cast<NameClass *>(operator new [](NUM_OBJECTS * sizeof *objects));

    for (unsigned i = 0; i < NUM_OBJECTS; i++) {
        objects[i].vectorName.resize(VEC_SIZE);
    }

    // Required to free memory
    operator delete[](objects);

    return 0;
}

If use vectors is not a problem, actually this works, and is really easy. It's a poem...

class-test.cpp

#include <stdio.h>
#include <algorithm>

#include "class.hpp"

int main( void )
{
  std::vector <NameClass> object(number_objects, NameClass(size));

  printf("%lu\n", object[0].vectorName.size() );

  return 0;
}

class.hpp

#include <vector>
#include <algorithm>

#include <vector>

class NameClass {
 public:
 NameClass() {} // default constructor

 explicit NameClass( unsigned size ){
    vectorName.resize( size );
 }
 std::vector <double> vectorName;
};

And if you want use arrays then just use the default constructor.

clas.hpp

#include <vector>

class NameClass {
 public:
 NameClass(unsigned size) {
 vectorName.resize( size ); 
 } // default constructor

 explicit NameClass( unsigned size ){ // eliminate this
    vectorName.resize( size );
 }
 std::vector <type> vectorName;
};

class-test.cpp

#include <stdio.h>

#include "class.hpp"

int main() {
  NameClass objects[2](4);

  printf("%lu\n", objects[0].vectorName.size());

  return 0;
}

this print a correct output.

You have to initialize every vector, it just how you present it in the code. you can do something this

std::vector<NameClass> classes(number_of_objects);
std::generate(classes.begin(), classes.end(), []{return NameClass(size);});

std::generate will initialize a instance of NameClass for each element of the vector.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM