Reputation: 664
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
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
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