2013-05-16 17 views
6

Dies ist nur ein Test-Projekt zu verstehen, wie die Vererbung funktioniert. Cat ist eine Unterklasse von Mammal, die wiederum eine Unterklasse von Animal ist.C++ löschen Zeiger-Array - doppelt frei oder Korruption

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

Also ich kann das nicht wirklich tun, denn dann bekomme ich das.

*** 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-Ausgang, wenn meine Konstruktoren und Destruktoren genannt werden, so dass, wenn meine Katzen geschaffen werde ich bekommen etwas wie folgt aus:

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

Wenn ich meinen Code ein wenig ändern, so heißt es:

delete [] *cats; 

dann habe ich erwartet, dass meine dtors wie dies für jede Katze aufgerufen:

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

stattdessen erhalte ich diese einzige Zeile:

Called dtor of Cat 

Zusammenfassung: Wie kann ich meine Arrays effektiv löschen, so dass alle mein dtors gecallt?

+1

Sie sollten wirklich zuerst über Zeiger und dynamische Zuordnung lesen. 'cats []' wird auf Stapel zugewiesen, Sie können es nicht "löschen". Stattdessen sollten Sie darüber iterieren und 'lösche' zu ​​jedem Element verwenden. –

+0

Verwenden Sie 'delete' nur, wenn Sie' new' verwendet haben. Sie haben Stapelzuordnung, lassen Sie es sich aufräumen. Erwägen Sie, etwas über 'std :: shared_ptr' und' std :: unique_ptr' zu erfahren - es ist einfacher zu lernen als die manuelle Speicherverwaltung. –

Antwort

2

Sie sollten nur delete[] auf Array, wenn Sie bekam dieses Array von new ...[]! Wie folgt:

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

Das obige wäre korrekt. Beachten Sie jedoch, dass Sie in diesem Fall keine Argumente an den Konstruktor übergeben können.

Jetzt ist Ihr Fall. Sie haben Array mit new nicht erstellt, so dass Sie das Array nicht selbst löschen sollten (es ist auf Stapel, nicht in Heap). Deshalb stürzt delete[] cats ab. Als nächstes behandelt, *cats Array als einen Zeiger und dereferenziert es, d. H. Gibt das Element zurück, auf das dieser Zeiger zeigt.Für Array ist es der Anfang des Arrays: *cats ist das gleiche wie cats[0]. Deshalb wird nur der erste Gegenstand beim zweiten Versuch gelöscht.

Schließlich, die Antwort: anstelle von all dem, löschen jedes Element einzeln. Für Ihren einfachen Fall:

delete cat1; 
delete cat2; 

Oder allgemeiner:

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

Hier sizeof(cats)/sizeof(cats[0]) ist ein einfacher Trick, um die Anzahl der Elemente im Array zu erhalten, indem seine Größe durch die Größe eines Elements geteilt wird.

Dadurch geben Sie den Speicher frei, in dem sich Ihre Cat Objekte befinden. Wenn Sie sich Sorgen um das Gedächtnis machen, wo Ihr Array von Zeigern liegt - es ist auf Stapel, was bedeutet, dass es automatisch bei der Rückkehr von der Funktion befreit wird.

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

delete[] cats würde nur würden, wenn Sie catscats = new Cat[num_cats] mit erstellt haben gearbeitet.

8

Diese

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

Erstellt ein Array von Zeigern auf Katzen, die mit Auto Lagerung! Sie haben das Array nicht mit new[] belegt, daher sollten Sie es nicht mit delete[] freigeben.

+0

hm, ich denke über diese Frage nach. Wie kann ich überprüfen, ob ein Zeiger auf ein Array ein Zeiger auf ein 'automatisches Speicher'-Array ist? – gaussblurinc

+0

@loldop, soweit ich weiß, gibt es keinen zuverlässigen Weg. Aus diesem Grund werden so viele Anstrengungen unternommen, um verschiedene Besitz-Semantiken zu implementieren. Die grundlegende Faustregel lautet: Geben Sie nur das frei, was Sie selbst zugewiesen haben, und wenn Sie etwas besitzen müssen, dokumentieren Sie dies entweder explizit oder klonen Sie es. – StoryTeller

+0

also, verwalten Sie nur diese Dinge, die Sie besitzen. gute Regel – gaussblurinc

0

Sie müssen das Array selbst nicht löschen, nur seine Elemente. Ihr Array cats ist auf dem Stapel, da Sie es nicht mit new oder malloc erstellt haben.

Also alles, was Sie tun müssen, ist

delete cat1; 
delete cat2; 

oder äquivalent

delete cats[0]; 
delete cats[1]; 
Verwandte Themen