Ungewollter Destruktoraufruf, warum?
-
Hallo Community,
Ich habe heute ein kleines Testprogramm geschrieben, bei dem ich eine verkettete Liste implementiere und bin dabei auf was merkwürdiges gestoßen, was ich mir nicht erklären kann. Der Code sieht (auf das Wesentliche reduziert) so aus:class Liste { private: Liste* next; public: Liste(Liste* Next = 0) : next(Next) {} ~Liste() {delete next;} Liste* Next() {return next;} Liste operator<<(Liste* secList) { //Die übergebene Liste an das letzte Element anhängen Liste* tempList = 0; for(tempList = this; tempList->Next() != 0; tempList = tempList->Next()); tempList->next = secList; return *this; } }; void main() { Liste* myList = new Liste(); *myList << new Liste() << new Liste() << new Liste(); }Wenn man den Code ausführt erhält man eine Exception. Ich habe das ganze mal debuggt und herausgefunden, dass nachdem myList durch die mit
new Liste()erzeugten Listen erweitert wurde, für alle Listenelemente, die eben an myList angehängt wurden der Destruktor aufgerufen wird.
Da das erste Element bereits alle nachfolgenen im Desktruktor löscht, wird eine Exception geworden, sobald das nächste Element mit delete gelöscht werden soll.
Soweit ist alles klar...Aber warum macht C++ sowas? Wieso wird auf die im Heap allokierten Listen ein delete aufgerufen?

Wenn ich den operator<< so modifiziere, dass er eine Referenz zurückgibt, funktioniert alles wunderbar
Liste& operator<<(Liste* secList) { ...Aber warum?
Thx
-
Soley schrieb:
Wenn ich den operator<< so modifiziere, dass er eine Referenz zurückgibt, funktioniert alles wunderbar
Und was ist der Unterschied? Wenn du per value zurückgibst, wird eine Kopie von *this erstellt. Was passiert mit dieser Kopie im weiteren Verlauf?
-
Danach wird auf diese Kopie wieder der <<operator aufgerufen und ein weiteres Element anghängt usw.
Wird diese Kopie vielleicht automatisch gelöscht, weil sie nach dem Aufruf von << ihre Gültigkeit verliert?
-
So in etwa. Versuch, die Lebenszeit mal genau zu verfolgen. Das Objekt wird beim Verlassen des innersten op<<-Aufrufs angelegt. Im aufrufenden Kontext gibst du diesem Objekt keinen Namen, es ist ein sogenannter rvalue. Nur ein Zeiger darauf existiert, nämlich als Parameter für den nächsten op<<-Aufruf. Nach dem Durchlaufen dieses op<<-Aufrufs ist das Objekt futsch.
-
Dann ergibt das alles natürlich einen Sinn.
Vielen Dank für die Erklärung
-
Mein Tipp: Einen Copy-Konstruktor und einen Zuweisungsoperator definieren, der alle Sub-Listen kopiert und die Klasse zu Listenelement umbenennen und eine Klasse Liste definieren, die die Elemente verwaltet (falls du das nicht schon gemacht hast).
-
Die Liste ist einfach grundsätzlich falsch. Eine List besteht aus Knoten, die eine eigene Klasse darstellen. Die Liste selbst bietet nur die Zugriffe.
-
Das sollte auch kein achsotollgroßes Projekt werden. Ich hab halt nur ein bissl rumgetestet und bin dann auf dieses Problem gestoßen, welches mich zum Grübeln gebracht hat.
Der Code sieht (auf das Wesentliche reduziert) so aus:
Die eigentliche Klasse besteht auch aus ein bisschen mehr, nur habe ich sie halt auf den funktionalen Kern reduziert, damit nicht diejenigen, die mir helfen könnten durch zig Zeilen code abgeschreckt werden
