Ich bin verwirrt darüber, wie man Destruktoren benutzt, wenn ich einen std :: vector meiner Klasse habe.
Also, wenn ich eine einfache Klasse wie folgt erstellen:
%Vor%Dann mache ich in meiner Hauptfunktion folgendes:
%Vor%Ich bekomme einen Laufzeitabsturz im Destruktor von Test, wenn ich den Gültigkeitsbereich verlassen habe. Warum ist das und wie kann ich meine Erinnerung sicher befreien?
Ihr Problem ist hier:
%Vor% Das Test()
erstellt ein temporäres Test
-Objekt, das dann in tObj
kopiert wird. An diesem Punkt wird sowohl tObj
als auch das temporäre Objekt big
gesetzt, um auf das Array zu zeigen. Dann wird das temporäre Objekt zerstört, welches den Destruktor aufruft und das Array zerstört. Wenn also tObj
zerstört wird, versucht es das bereits zerstörte Array wieder zu zerstören.
Wenn tVec
zerstört wird, zerstört es außerdem seine Elemente, so dass das bereits zerstörte Array wieder zerstört wird.
Sie sollten einen Kopierkonstruktor und einen Zuweisungsoperator definieren, damit beim Kopieren eines Test
-Objekts das big
-Array kopiert wird oder eine Art von Referenzzählung hat, so dass es erst bei allen Besitzern zerstört wird sind zerstört.
Eine einfache Lösung besteht darin, Ihre Klasse so zu definieren:
%Vor% In diesem Fall müssten Sie keinen Destruktor, keinen Kopierkonstruktor oder keinen Zuweisungsoperator definieren, da das std::vector<>
-Member alles übernimmt. (Beachten Sie jedoch, dass 10.000 Byte zugewiesen und kopiert werden, wenn Sie eine Instanz von Test
kopieren.)
Das Problem besteht darin, dass Sie keinen Kopierkonstruktor für Test
definieren. Der Compiler generiert also einen Standard-Kopierkonstruktor für Sie, der nur den Inhalt des Objekts kopiert - in diesem Fall den Zeiger int.
Wenn Sie jetzt Ihr Objekt in den Vektor zurückschieben, wird es implizit mit dem Kopierkonstruktor kopiert. Dies führt dazu, dass zwei Objekte auf dasselbe Array von Ints verweisen! Am Ende versuchen zwei Destruktoren, das gleiche Array zu löschen - BANG.
Immer wenn Sie eine Klasse definieren, die Mitglieder über Zeiger * besitzt, müssen Sie neben dem Destruktor auch einen Kopierkonstruktor für definieren . Update: und ein Zuweisungsoperator, aus dem gleichen Grund (Danke @James: -)
Update2: Ein einfacher Weg, um alle diese Einschränkungen zu umgehen, besteht darin, ein statisches Array anstelle des dynamisch zugewiesenen zu definieren:
%Vor% Am besten verwenden Sie jedoch std::vector<int>
anstelle eines Arrays.
* Das heißt, enthält Zeiger auf Mitglieder mit Besitz Semantik (dank @Steve Jessop zur Klärung)
Ohne einen Kopierkonstruktor erstellt der Vektor eine flache Kopie Ihres Objekts. Dies führt zu zwei Objekten vom Typ Test
, die auf das gleiche Array big
verweisen. Die erste Instanz löscht das Array, wenn es zerstört wird, und dann versucht die zweite Instanz, einen gelöschten Zeiger zu dereferenzieren, was ein undefiniertes Verhalten ist.
Das ist falsch und sollte so sein, wie es keine Kopien erstellt:
%Vor%Dies schafft auch eine Menge Kopien:
%Vor%Wenn Sie also ein int-Array freigeben, werden Sie alle Arrays freigeben. Und das folgende Löschen wird fehlschlagen.
Was Sie brauchen, ist entweder:
Verwenden Sie einen Kopierkonstruktor, um für jede Klasse ein eigenes Array zu haben
Warum einen Zeiger verwenden?
%Vor%
Das wird gut funktionieren.
Tags und Links memory c++ vector destructor