tsusanka
tsusanka

Reputation: 4841

C++ array of pointer memory leaks

In my class I have a dynamically allocated array of pointers. My declaration:

 array = new Elem* [size];
 for (int i = 0; i < size; i++) {
    array[i] = NULL;
 }

So there is an array of pointers, where each pointer points to a simple Elem struct.

The main question is, how should I properly deallocate the array. If I use only:

for (int i = 0; i < size; i++) {
   delete array[i];
}

Valgrind reports 1 not-freed block, which is traced to the line where 'array = new Elem* [size];' states.

On the other hand if I add to the previous code:

delete array;

Which I thought is correct, valgrind reports 0 not-freed blocks, which is perfect, BUT it reports

Mismatched free() / delete / delete []

exactly on the line where 'delete array;' is. I tried 'delete []array' too, but that's just "1 not-freed blocks" too then! If somebody could explain me the proper way it would be much appreciated.

EDIT: So using:

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

is working probably fine. It is working in one of my classes (I have two similar) the other still reports some small leak. I would think it's just a minor bug somewhere, but valgrind still points to the line where

array = new Elem* [size];

stands.

EDIT2: I solved this as well, thank you for your exhausting contribution!!

Upvotes: 2

Views: 2650

Answers (4)

Mark Ransom
Mark Ransom

Reputation: 308158

You need:

delete [] array;

Because it's an array.

I just noticed your note that you tried this too - it's the proper thing to do so I don't know why you'd still be getting an error.

Edit: This deserves a more thorough explanation.

When you create a pointer using new, the pointer may be to a single element or an array of elements depending on the syntax you use. But the pointer type is the same in both cases! The compiler relies on you to know what the pointer points to and treat it accordingly.

Elem ** single = new Elem*;    // pointer to one pointer
single[0] = new Elem;          // OK
single[1] = new Elem;          // runtime error, but not compile time

Elem ** array = new Elem* [2]; // pointer to array of pointers
array[0] = new Elem;           // OK
array[1] = new Elem;           // OK

When you delete a pointer, the destructor is called for the object it points to or for each element of the array. But since the pointer type is the same in each case, the compiler relies on you to give it the proper syntax so it knows what to do.

delete single;
delete [] array;

In your case the elements of the array are pointers also, and pointers don't have destructors. That means those pointers won't be deleted and will become memory leaks if you don't delete them first. You were correct to have a loop to delete them individually before the final delete.

Upvotes: 8

David Heffernan
David Heffernan

Reputation: 612954

The syntax for deleting an array is like this:

delete[] array;

Your for loop to delete the objects pointed to by the elements of the array is fine. The deletion of the array itself is the only problem. You need both the for loop and then the delete[] to dispose of the array itself.

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

I suspect that you have tried using the for loop, or the delete[], but not both together. And if when you do that you still have leaks or errors, then you would need to show us the code that allocates the pointers that are elements of the array.


Using std::vector<> instead of an array would mean that you could stop worrying about these nitty gritty details and move to higher level of abstraction.

Upvotes: 5

Greg Hewgill
Greg Hewgill

Reputation: 993085

In this case, you need both.

for (int i = 0; i < size; i++) {
   delete array[i];
}
delete[] array;

You call delete exactly once for each time you called new.

Note that although you need to call delete[] array here (because you allocated it with new[]), the delete[] operator does not call the destructors on the objects pointed to by elements of the array. This is because the delete[] operator calls destructors on objects in the array, and your array contains pointers but not objects. Pointers do not themselves have destructors.

Upvotes: 2

Pubby
Pubby

Reputation: 53047

You should free everything in the array (if dynamically allocated) and then free the array itself.

for (int i = 0; i < size; i++) { // only free inside if dynamically allocated - not if just storing pointers
   delete array[i];
}
delete[] array; // necesarry

Upvotes: 7

Related Questions