RigidBody
RigidBody

Reputation: 664

c++ How to deallocate and delete a 2D array of pointers to objects

In SO question [How to allocate a 2D array of pointers in C++] [1], the accepted answer also makes note of the correct procedure of how to de-allocate and delete said array, namely "Be careful to delete the contained pointers, the row arrays, and the column array all separately and in the correct order." So, I've been successfully using this 2D array in a cellular automaton simulation program. I cannot, however, get this array's memory management correct. I do not see an SO answer for how to do this other than the reference above.

I allocate the 2D array as follows:

Object*** matrix_0 = new Object**[rows];
    for (int i = 0; i < rows; i++) {
        matrix_0[i] = new Object*[cols];
    }

My futile attempt(s) (according to Valgrind) to properly de-allocate the above array are as follows:

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        matrix_0[i][j] = NULL;
    }
}
delete [] matrix_0;
matrix_0 = NULL;

Clearly, I'm missing the rows and cols part as reference [1] suggests. Can you show me what I'm missing? Thanks in advance.

[1]: (20 Nov 2009) How to allocate a 2D array of pointers in C++

Upvotes: 0

Views: 12260

Answers (2)

user4581301
user4581301

Reputation: 33932

You have a tonne of deleting to do in this:

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        delete matrix_0[i][j]; // delete stored pointer
    }
    delete[] matrix_0[i]; // delete sub array
}
delete [] matrix_0; //delete outer array
matrix_0 = NULL;

There is no need to NULL anything except matrix_0 because they are gone after delete.

This is horrible and unnecessary. Use a std::vector and seriously reconsider the pointer to the contained object.

std::vector<std::vector<Object*>> matrix_0(rows, std::vector<Object*>(cols));

Gets what you want and reduces the delete work to

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        delete matrix_0[i][j]; // delete stored pointer
    }
}

But SergeyA's suggestion of storing unique_ptr, std::vector<std::vector<std::unique_ptr<Object>>> matrix_0; reduces the deletions required to 0.

Since speed is one of OP's goals, there is one more improvement:

std::vector<std::unique_ptr<Object>> matrix_0(rows * cols);

Access is

matrix_0[row * cols + col];

This trades a bit of visible math for the invisible math and pointer dereferences currently going on behind the scenes. The important part is the vector is now stored as a nice contiguous block of memory increasing spacial locality and reducing the number of cache misses. It can't help with the misses that will result from the pointers to Objects being scattered throughout memory, but you can't always win.

A note on vector vs array. Once a vector has been built, and in this case it's all done in one shot here:

std::vector<std::unique_ptr<Object>> matrix_0(rows * cols);

all a vector is is a pointer to an and a couple other pointers to mark end and the the location of the last location used. Access to the data array is no different from access to a dynamic array made with new. Using the index operator [] compiles down to data_pointer + index exactly the same as using [] on an array. There is no synchronizing or the like as in Java's Vector. It is just plain raw math.

Compared to a dynamic array all a preallocated vector costs you is two pointers worth of memory and in return you get as close to no memory management woes as you are likely to ever see.

Upvotes: 9

Rakete1111
Rakete1111

Reputation: 48928

Before setting the pointers to NULL, you should delete them first. After every pointer in the column are deleted, you can delete[] the row and set it to NULL, as every element is deleted and gone.

Upvotes: 0

Related Questions