0

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

Community
  • 1
  • 1
Moises Rojo
  • 371
  • 2
  • 14
  • `NameClass object[ number_objects ] = {NameClass(size)}` should work I think – Telokis Mar 13 '17 at 16:32
  • 2
    @Ninetainedo No, [this will only init the first one](http://coliru.stacked-crooked.com/a/93420d6f114844d9) (The rest are default initialized) – Borgleader Mar 13 '17 at 16:35
  • @Borgleader: Technically, the rest are value-initialized. For `vector`, the result is the same. – Nicol Bolas Mar 13 '17 at 16:36
  • 1
    Possible duplicate of https://stackoverflow.com/questions/4754763/object-array-initialization-without-default-constructor – smac89 Mar 13 '17 at 23:45

4 Answers4

1

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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Is interesting but... In the way that I'm walking, is much more easy just use a for loop and asigne every size of the vector, use few code and is easy to understand. `object[i].vectorName.resize( size );` from i = 0, to i < number_objects. I will keep thinking, you solution is c++14 And I have much to learn so... I will study a bit more you amazing c++14 code. maybe is just that I don't understand it. – Moises Rojo Mar 13 '17 at 18:42
1

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;
}
smac89
  • 39,374
  • 15
  • 132
  • 179
  • The but the implementation is... How? You put the same main, so I can't understand what's is the difference with the default constructor. – Moises Rojo Mar 13 '17 at 23:49
  • @MoisesRojo, the default constructor is what allows you to declare an array of such items. Without it, the compiler does not have all the necessary information to define an array of `NameClass`. I posted something further to show how you can do without the default constructor and without any stl containers but only by using some fancy C-like constructs – smac89 Mar 13 '17 at 23:55
1

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.

Moises Rojo
  • 371
  • 2
  • 14
0

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.

saykou
  • 167
  • 1
  • 9
  • `g++ class-main.cpp` have problems. In file included from class-main.cpp:4:0: class.hpp:7:12: note: candidate: NameClass::NameClass(unsigned int) explicit NameClass( unsigned size ) ^~~~~~~~~ class.hpp:7:12: note: candidate expects 1 argument, 0 provided class.hpp:4:7: note: candidate: NameClass::NameClass(const NameClass&) class NameClass ^~~~~~~~~ – Moises Rojo Mar 13 '17 at 17:55
  • 1
    If you use `std::vector`, simply do `std::vector classes(number_of_objects, NameClass(size));`. – Jarod42 Mar 13 '17 at 20:10