How to Dynamically Declare an Array of Objects with a Constructor in C++

how to dynamically declare an array of objects with a constructor in c++

MyClass *myVar;
myVar = new MyClass[num];

Actually in this form you cannot invoke constructor which takes parameter(s). It is not allowed by the language specification.

However, if you use std::vector, which I recommend you to use, then you can create a vector calling non-default constructor as:

#include <vector> //header file where std::vector is defined

std::vector<MyClass> arr(num, MyClass(10,20));

It creates a vector of num elements, each element is created by calling copy-constructor of the class, passing MyClass(10,20) as argument to it.

The vector is also good because now you dont need to manage memory yourself. Neither manual allocation, nor manual deallocation. Plus, you can know the number of elements by calling arr.size() anytime. You always know how many elements the vector contains. You can also add elements anytime, just by calling .push_back() member function as:

arr.push_back(MyClass(20,30)); 

And now you can access elements, just like you access array, i.e by using index:

f(arr[i]); // 0 <= i < arr.size();

Additionally, you can use iterators which facilitate idiomatic programming, enabling you to use various algorithmic functions from <algorithm> header as:

#include <algorithm> //header file where std::for_each is defined

std::for_each(arr.begin(), arr.end(), f);

where f is function which takes one argument of type MyClass& (or MyClass const &) depending on what you want to do in f.

In C++11, you can use lambda as:

std::for_each(arr.begin(), arr.end(), [](const MyClass & m)
{
//working with m
});

How can I initialize objects in a dynamically allocated array with some arguments

you can use std::vector.

If you still want to use arrays, you can use

Circle *arr = new Circle[5]{10}; which initializes first radius to 10 and use default for others.

Sample output will be:

radius : 10
radius : 0
radius : 0
radius : 0
radius : 0
deleted
deleted
deleted
deleted
deleted

If you want a single line solution you can use this dirty line:

Circle *arr = new Circle[5]{10,10,10,10,10};

new array of objects with constructor that needs parameters in C++

I need to create a Network of n layers, each containing a different number of neurons (passed as an array of length n):

You won't be able to do that with a fixed array of Layer objects. Although there is a syntax available for the new[] operator to initialize all of the elements of the allocated array with the same constructor value, there is no syntax for initializing them with different values, at least not when the values are coming from another array.

To do what you are asking for, you will have to create an array of Layer* pointers (or better, an array of std::unique_ptr<Layer> objects in C++11 and later), and then dynamically create each Layer object with a different constructor value as needed. You were close in doing that, but you are just missing an extra layer of indirection in your array declaration:

class Network {
private:
unsigned int _nb_layers;
Layer** _layers; // <-- DYNAMIC ARRAY OF POINTERS, NOT OBJECTS!

public:
Network(unsigned int nb_layers, unsigned int* nb_neurons);
~Network();

const Layer* getLayer(unsigned int index) const;
};

Network::Network(unsigned int nb_layers, unsigned int *nb_neurons) {
_nb_layers = nb_layers;
_layers = new Layer*[nb_layers]; // <-- ALLOCATE ARRAY OF POINTERS FIRST

for(int i = 0; i < nb_layers; i++) {
_layers[i] = new Layer(nb_neurons[i]); // <-- THEN MAKE EACH POINTER POINT TO AN OBJECT
}
}

const Layer* Network::getLayer(unsigned int index) const {
Expects(index < _nb_layers);

return _layers[index];
}

Network::~Network() {
for (int i = 0; i < _nb_layers; ++i)
delete _layers[i]; // <-- NEED TO FREE EACH OBJECT FIRST
delete[] _layers; // <-- THEN FREE THE ARRAY ITSELF
}

In C++11 and later, you can do this instead:

class Network {
private:
unsigned int _nb_layers;
std::unique_ptr<std::unique_ptr<Layer>[]> _layers;

public:
Network(unsigned int nb_layers, unsigned int* nb_neurons);
// ~Network(); // <-- NOT NEEDED!

const Layer* getLayer(unsigned int index) const;
};

Network::Network(unsigned int nb_layers, unsigned int *nb_neurons) {
_nb_layers = nb_layers;
_layers.reset( new std::unique_ptr<Layer>[nb_layers] );

for(int i = 0; i < nb_layers; i++) {
_layers[i].reset( new Layer(nb_neurons[i]) );
// or, in C++14 and later:
// _layers[i] = std::make_unique<Layer>(nb_neurons[i]);
}
}

const Layer* Network::getLayer(unsigned int index) const {
Expects(index < _nb_layers);

return _layers[index].get();
}

/*
Network::~Network()
{
// NOTHING TO DO HERE!
}
*/

And BTW, both of your classes are violating the Rule of 3/5/0. Neither of the classes is implementing a copy constructor or a copy assignment operator in order to make copies of their respective arrays from one class instance to another. Or, in the case of C++11 and later, a move constructor and a move assignment operator to move their respective arrays from one class instance to another.

Why can't one dynamically declare an array of objects in C++ like this :

The "proper" way is to use std::vector. It is a fast, safe, more robust alternative to horrible new.

std::vector<Character> vec;
vec.push_back(Character(params));
vec.push_back(Character(other_params));

If you know the size ahead, you can avoid reallocation overhead by using std::vector::reserve

std::vector<Character> vec;
vec.reserve(50);
vec.push_back(Character(params));
vec.push_back(Character(other_params));

The overhead of std::vector is practically non-existent.

Now, the reason why you can't do this your way, it's because by default new uses default constructor, and it doesn't exist.

How do I dynamically allocate an array of objects in C++ with individual constructor parametes for each object?

I see three possibilities:

  • Use vector with reserve + emplace_back. You have the guarantee that your elements don't get moved as long as you don't exceed the capacity.
  • Use malloc + placement new. This allows you to allocate raw memory and then construct each element one by one e.g. in a loop.
  • If you already have a range of parameters from which to construct you objects as in the example, you can brobably (depending on your implementation of std::vector) use std::vector's iterator based constructor like this:

    std::vector<Foo> v(parameters.begin(),parameters.end());

First solution has the advantage to be much simpler and has all the other goodies of a vector like taking care of destruction, keeping the size around etc.
The second solution might be faster, because you don't need to do the housekeeping stuff of vector emplace_back and it works even with a deleted move / copy constructor if that is important to you, but it leaves you with dozens of possibilities for errors

The third solution - if applicable - is imho the best. It also works with deleted copy / move constructors, should not have any performance overhead and it gives you all the advantages of using a standard container.

It does however rely on the constructor first determining the size of the range (e.g. via std::distance) and I'm not sure if this is guaranteed for any kind of iterators (in practice, all implementations do this at least for random access iterators). Also in some cases, providing appropriate iterators requires writing some boilerplate code.

How to dynamically allocate array of objects using parameterized constructor?

You could use placement-new as:

typedef std::aligned_storage<sizeof(SimpleClass), 
std::alignment_of<SimpleClass>::value
>::type storage_type;

//first get the aligned uninitialized memory!
SimpleClass *p1 = reinterpret_cast<SimpleClass*>(new storage_type[N]);

//then use placement new to construct the objects
for(size_t i = 0; i < N ; i++)
new (p1+i) SimpleClass(i * 10);

In this example, I'm passing (i * 10) to the constructor of SampleClass.

  • Online Demo

Hope that helps.

parameterized constructor with dynamic array of object

In create, you fully replace the previous B objects with brand new ones using the 2 parameters constructor... which just leaves the A object member default initialized.

What could be done to fix?

  1. Pass the parameters of B to A ctor:

     B::B (int a, string b): object(a, b)
    {
    bbb = a;
    name = b;
    }

    That way you initialize the A object member with the same parameters as its parent

  2. Reset the A object member to its previous value:

     void create (B * &obj2, int siz)
    {
    std::cout << obj2[0].get_nn (); //this will run fine
    for (int i = 0; i < siz; i++) {
    A old = obj2[i].object;
    obj2[i] = B (10, "pranjal"); //this will also run fine
    obj2[i].object = old;
    }
    std::cout << obj2[0].get_nn ();
    }

    But as it requires accesses to private members, create should be declared friend in B class:

     class B {
    ...
    friend void create (B * &obj2, int siz);
    };

How can i call the parameterized constructor for all objects in my dynamic array of objects on allocation in c++?

The simplest solution to this problem would be to use std::vector which handles all those problems internally, e.g.:

#include <vector>
// skipping class declaration for brevity
int main (void)
{
int size = 3, parameter = 10;
std::vector<foo> array;
array.reserve(size);

cout << endl;

for (int i = 0; i < size; i++)
array.emplace_back(parameter);

cout << endl;

return 0;
}

However, if for some reason you want/need to do this by hand then you should be allocating a "raw buffer" and construct objects inside that buffer with placement new - this will however also require you to manually call the destructors

One possible example, doing everything "manually" could look like this

int main (void)
{
int size = 3, parameter = 10;
foo *array = reinterpret_cast<foo*>(new char[size * sizeof(foo)]);

cout << endl;

for (int i = 0; i < size; i++)
new (&array[i]) foo(parameter);

cout << endl;

for (int i = 0; i < size; i++)
array[i].~foo();

delete[] reinterpret_cast<char*>(array);
return 0;
}

An arguably cleaner solution is to use std::allocator and std::allocator_traits - this would look like this

#include <memory>
// skipping class declaration
int main (void)
{
std::allocator<foo> alloc;
using alloc_t = std::allocator_traits<decltype(alloc)>;
int size = 3, parameter = 10;
foo *array;
array = alloc_t::allocate(alloc, size);

cout << endl;

for (int i = 0; i < size; i++)
alloc_t::construct(alloc, &array[i], parameter);

cout << endl;

for (int i = 0; i < size; i++)
alloc_t::destroy(alloc, &array[i]);

alloc_t::deallocate(alloc, array, size);
return 0;
}

Creation of Dynamic Array of Dynamic Objects in C++

If you are using c++ then you shouldn't reinvent the wheel, just use vectors:

#include <vector>

std::vector< std::vector< Stock > > StockVector;

// do this as many times as you wish
StockVector.push_back( std::vector< Stock >() );

// Now you are adding a stock to the i-th stockarray
StockVector[i].push_back( Stock() );

Edit:

I didn't understand your question, if you just want to have and array of arrays allocated on the heap just use:

Stock** StockArrayArray = new Stock*[n]; // where n is number of arrays to create
for( int i = 0; i < n; ++i )
{
StockArrayArray[i] = new Stock[25];
}

// for freeing
for( int i = 0; i < n; ++i )
{
delete[] StockArrayArray[i];
}
delete[] StockArrayArray;


Related Topics



Leave a reply



Submit