Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ delete pointer array - double free or corruption

Tags:

c++

This is just a test project to understand how inheritance works. Cat is a subclass of Mammal, which again is a subclass of Animal.

int main()
{
    Cat* cat1 = new Cat("nosy grey", 1.0d, 3);
    Cat* cat2 = new Cat("purply green", 2.0d, 4);

    Cat* cats[] = {cat1, cat2};

    delete [] cats;
 }

So I can't really do that, because then I get this.

*** Error in `/home/max/git/info-2-ss/Blatt3/Aufgabe2/main.exe': double free or corruption (out): 0x00007fff55fd7b10 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x80a46)[0x7f3a07452a46]
/home/max/git/info-2-ss/Blatt3/Aufgabe2/main.exe[0x40178e]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7f3a073f3ea5]
/home/max/git/info-2-ss/Blatt3/Aufgabe2/main.exe[0x400d39]

I output when my constructors and destructors are called, so when my Cats get created I get something like this:

Called ctor of Animal with age: 3
Called ctor of Mammal with hairLength: 1
Called ctor of Cat with eyecolor: nosy grey

When I change my code a bit so it reads:

delete [] *cats;

then I would've expected that my dtors get called like this for every Cat:

Called dtor of Cat
Called dtor of Mammal 
Called dtor of Animal 

instead I get this single line:

Called dtor of Cat

Summary: How can I effectively delete my arrays, so that all my dtors get called?

like image 998
Diemex Avatar asked May 16 '13 12:05

Diemex


3 Answers

This

Cat* cats[] = {cat1, cat2};

Creates an array of pointers to cats with auto storage! You didn't allocate the array with new[], so you shouldn't release it with delete[].

like image 106
StoryTeller - Unslander Monica Avatar answered Sep 17 '22 23:09

StoryTeller - Unslander Monica


You should use delete[] on array only if you got this array from new ...[]! Like this:

Cat * cats = new Cat[2];
delete [] cats;

The above would be correct. But note that, of course, in this case you cannot pass arguments to constructor.

Now, your case. You didn't create array with new, so you should not delete the array itself (it is on stack, not in heap). That's why delete[] cats crashes. Next, *cats treats array as a pointer and dereferenses it, i.e. returns the item this pointer points to. For array it is the beginning of the array: *cats is the same as cats[0]. That's why only first item gets deleted in your second try.

Finally, the answer: instead of all this, delete each item individually. For your simple case:

delete cat1;
delete cat2;

Or, more generally:

for(int i = 0; i < sizeof(cats)/sizeof(cats[0]); ++i) {
    delete cats[i];
}

Here sizeof(cats)/sizeof(cats[0]) is a simple trick to get the number of items in array by dividing its size by the size of an element.

By this you free the memory where each of your Cat objects is placed. If you are worried about the memory where your array of pointers lays — it is on stack, which means that it will be freed automaticaly on return from the function.

like image 39
NIA Avatar answered Sep 18 '22 23:09

NIA


for(i = 0; i < len(cats)/sizeof(Cat); i++) {
  delete cats[i];
}

delete[] cats would have worked only if you'd created cats using cats = new Cat[num_cats].

like image 32
Anubhav C Avatar answered Sep 19 '22 23:09

Anubhav C