Dynamically Allocating an Array of Objects

Dynamically allocating an array of objects

For building containers you obviously want to use one of the standard containers (such as a std::vector). But this is a perfect example of the things you need to consider when your object contains RAW pointers.

If your object has a RAW pointer then you need to remember the rule of 3 (now the rule of 5 in C++11).

  • Constructor
  • Destructor
  • Copy Constructor
  • Assignment Operator
  • Move Constructor (C++11)
  • Move Assignment (C++11)

This is because if not defined the compiler will generate its own version of these methods (see below). The compiler generated versions are not always useful when dealing with RAW pointers.

The copy constructor is the hard one to get correct (it's non trivial if you want to provide the strong exception guarantee). The Assignment operator can be defined in terms of the Copy Constructor as you can use the copy and swap idiom internally.

See below for full details on the absolute minimum for a class containing a pointer to an array of integers.

Knowing that it is non trivial to get it correct you should consider using std::vector rather than a pointer to an array of integers. The vector is easy to use (and expand) and covers all the problems associated with exceptions. Compare the following class with the definition of A below.

class A
{
std::vector<int> mArray;
public:
A(){}
A(size_t s) :mArray(s) {}
};

Looking at your problem:

A* arrayOfAs = new A[5];
for (int i = 0; i < 5; ++i)
{
// As you surmised the problem is on this line.
arrayOfAs[i] = A(3);

// What is happening:
// 1) A(3) Build your A object (fine)
// 2) A::operator=(A const&) is called to assign the value
// onto the result of the array access. Because you did
// not define this operator the compiler generated one is
// used.
}

The compiler generated assignment operator is fine for nearly all situations, but when RAW pointers are in play you need to pay attention. In your case it is causing a problem because of the shallow copy problem. You have ended up with two objects that contain pointers to the same piece of memory. When the A(3) goes out of scope at the end of the loop it calls delete [] on its pointer. Thus the other object (in the array) now contains a pointer to memory that has been returned to the system.

The compiler generated copy constructor; copies each member variable by using that members copy constructor. For pointers this just means the pointer value is copied from the source object to the destination object (hence shallow copy).

The compiler generated assignment operator; copies each member variable by using that members assignment operator. For pointers this just means the pointer value is copied from the source object to the destination object (hence shallow copy).

So the minimum for a class that contains a pointer:

class A
{
size_t mSize;
int* mArray;
public:
// Simple constructor/destructor are obvious.
A(size_t s = 0) {mSize=s;mArray = new int[mSize];}
~A() {delete [] mArray;}

// Copy constructor needs more work
A(A const& copy)
{
mSize = copy.mSize;
mArray = new int[copy.mSize];

// Don't need to worry about copying integers.
// But if the object has a copy constructor then
// it would also need to worry about throws from the copy constructor.
std::copy(©.mArray[0],©.mArray[c.mSize],mArray);

}

// Define assignment operator in terms of the copy constructor
// Modified: There is a slight twist to the copy swap idiom, that you can
// Remove the manual copy made by passing the rhs by value thus
// providing an implicit copy generated by the compiler.
A& operator=(A rhs) // Pass by value (thus generating a copy)
{
rhs.swap(*this); // Now swap data with the copy.
// The rhs parameter will delete the array when it
// goes out of scope at the end of the function
return *this;
}
void swap(A& s) noexcept
{
using std::swap;
swap(this.mArray,s.mArray);
swap(this.mSize ,s.mSize);
}

// C++11
A(A&& src) noexcept
: mSize(0)
, mArray(NULL)
{
src.swap(*this);
}
A& operator=(A&& src) noexcept
{
src.swap(*this); // You are moving the state of the src object
// into this one. The state of the src object
// after the move must be valid but indeterminate.
//
// The easiest way to do this is to swap the states
// of the two objects.
//
// Note: Doing any operation on src after a move
// is risky (apart from destroy) until you put it
// into a specific state. Your object should have
// appropriate methods for this.
//
// Example: Assignment (operator = should work).
// std::vector() has clear() which sets
// a specific state without needing to
// know the current state.
return *this;
}
}

Dynamically allocating array of objects

You have allocated space for dcArrPtr, but didn't allocate every object in this array. You must do following:

Server::Server(int x, int y, int count)
{
dcPtr = new DizzyCreature[count];

dcArrPtr = new DizzyCreature*[count];
for ( int i = 0; i < count; i++ ) {
dcArrPtr[ i ] = new DizzyCreature;
}
_count = count;
}

Server::~Server(void)
{
for ( int i = 0; i < count; i++ ) {
delete dcArrPtr[ i ];
}
delete[] *dcArrPtr;
delete[] dcPtr;
}

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};

Dynamically allocating array of objects like int

You can do it using this line:

A* a = new A[N];

How it works?

the new keyword will allocate N sequential block in the heap. Each block has a size of sizeof(A) so the total size in bytes is N*sizeof(A). Allocating those objects in memory is ensured done by calling the default constructor N times.

Alternative:

Use std::vector instead. It will do all the work for you.

How to create a dynamically allocated array of objects and not use the default constructor?

new expression allows only default initialization, you can not do this within single new expression. What you could do is allocate raw memory and construct objects one by one using placement new (see this answer in Object array initialization without default constructor)

Or yet even better, don't use C-style arrays. Instead, use some STL container such as std::vector and it's constructor, where the 2nd argument is a value that will be used to initialize elements:

std::vector<IntegerSet> integers(5, IntegerSet(this->getLength()) );

Dynamically allocating an array of objects to a pointer using new: potentially uninitialized pointer

There are at least two issues with your code here:

   try
{
p_employee_database = new employee_bonus_record[employee_quantity];
}
catch (bad_alloc xa)
{
fatal_error(EMPLOYEE_ALLOC_ERR, "get_employee_records_database",
"employee bonus records database");
}
//.. rest of code, assuming p_employee_database is ok.

If the exception is thrown, the p_employee_database is uninitialized, however you failed to return from the function. Instead your logic proceeds using p_employee_database as if nothing is wrong, thus the compiler warning.

Even as you stated, fatal_error calls exit(), the compiler doesn't see this. It only looks at that block of code and gives the warning. If you want to suppress the warning, you can return nullptr.

   try
{
p_employee_database = new employee_bonus_record[employee_quantity];
}
catch (const bad_alloc& xa)
{
fatal_error(EMPLOYEE_ALLOC_ERR, "get_employee_records_database",
"employee bonus records database");
return nullptr;
}

The second thing wrong with the code is that you should catch the std::bad_alloc by const reference, not by value. See this article.

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.



Related Topics



Leave a reply



Submit