Frage

Ein paar Stunden zurück Ich war mit einem Speicherverlust Problem Hantieren und es stellte sich heraus, dass ich wirklich einige grundlegende Dinge über virtuelle Destruktoren falsch! Lassen Sie mich erklären legte meine Klasse Design.

class Base
{
  virtual push_elements()
  {}
};

class Derived:public Base
{
vector<int> x;
public:
   void push_elements(){ 
      for(int i=0;i <5;i++)
         x.push_back(i); 
   }
};

void main()
{
    Base* b = new Derived();
    b->push_elements();
    delete b;
}

Die Grenzprüfeinrichtung Werkzeug berichtete einen Speicherverlust in der abgeleiteten Klasse Vektor. Und ich herausgefunden, dass der Destruktor nicht virtuell ist und die abgeleitete Klasse destructor wird nicht aufgerufen. Und es wurde überraschend festgelegt, wenn ich das Destruktor virtuell gemacht. Ist das nicht der Vektor freigegeben wird automatisch auch wenn die abgeleitete Klasse destructor nicht genannt? Ist das eine Marotte in Bounds Werkzeug oder ist mein Verständnis von virtuellem Destruktor falsch?

War es hilfreich?

Lösung

eine abgeleitete Klasse Objekt durch eine Basisklasse Zeiger löschen, wenn die Basisklasse keinen virtuellen Destruktor führt zu undefinierten Verhalten haben.

Was Sie beobachtet haben (dass der abgeleitete Klasse Teil des Objekts wird nie zerstört und damit seine Mitglieder nie deallokierten bekommen) ist wahrscheinlich die am häufigsten von vielen möglichen Verhaltensweisen und ein gutes Beispiel dafür, warum es wichtig ist, um sicherzustellen, Ihre Destruktoren sind virtuelle, wenn Sie Polymorphismus auf diese Weise verwendet werden.

Andere Tipps

Wenn die Basisklasse keinen virtuellen Destruktor hat, dann ist das Ergebnis des Codes ist nicht definiertes Verhalten, die nicht unbedingt der falsche destructor genannt zu werden. Dies ist vermutlich, was Bounds ist die Diagnose.

Obwohl dies technisch nicht definiert ist, müssen Sie noch die am weitesten verbreitete Methode des Scheiterns, um zu wissen, dass es zu diagnostizieren. Die übliche Methode des Scheiterns ist der falschen destructor zu nennen. Ich weiß nicht, von der Anwendung, die auf andere Weise fehl, obwohl zugegebenermaßen nur ich zwei Implementierungen verwenden.

Der Grund, warum dies geschieht, ist aus dem gleichen Grund die ‚falsche‘ Funktion aufgerufen wird erhalten, wenn Sie versuchen, eine nicht-virtuelle Member-Funktion außer Kraft zu setzen und sie durch einen Basiszeiger nennen.

Wenn der Destruktor nicht virtuell ist, dann wird die Basis destructor aufgerufen werden. Die Basis destructor reinigt das Basisobjekt und Oberflächen auf. Es gibt keine Möglichkeit für das Basisobjekt destructor über das abgeleitete Objekt zu wissen, es muss der abgeleitete destructor genannt werden, und die Art und Weise, das zu tun, wie bei jeder Funktion ist der Destruktor virtuell zu machen.

Von der C ++ FAQ Lite: "Wann sollte mein destructor virtuell sein?" Lesen Sie es hier . (C ++ FAQ Lite ist eine ausgezeichnete Quelle für alle Ihre Fragen im Zusammenhang mit C ++, übrigens).

In C ++, ein trivial destructor ist ein rekursiv definiert Konzept - es ist ein destructor, dass der Compiler für Sie geschrieben, wenn jedes Mitglied der Klasse (und jede Basisklasse) eine triviale destructor hat. (Es gibt ein ähnliches Konzept des trivialen Konstruktor aufgerufen.)

Wenn ein Objekt mit einem nicht-trivialen destructor in einem Objekt enthalten ist (wie die vector in Ihrem Beispiel), dann der destructor des äußeren Objekts (wie Ihr Derived) in nicht mehr trivial. Auch wenn Sie keine Schreib destructor hat, der C ++ Compiler automatisch schrieb einen destructor, die die Destruktoren aller Mitglieder aufruft, die Destruktoren haben.

Also, auch wenn Sie nicht schreiben etwas, die Vorbehalte des Schreibens ein nicht-virtuellen Destruktor gelten weiterhin.

, wenn Sie von c # kommen, dann waren Sie direkt fragen, warum ist Vektor nicht automatisch freigegeben. Aber in C ++ ist die automatische Speicherverwaltung nicht availble, wenn Sie die Microsoft manged Extesions zu C ++ verwenden (C ++ / CLI).

, da es keine destructor in Basisklasse ist, die virtuell ist, wird die abgeleitete Klasse Objekt nie freigegeben werden und dort-by Sie den Speicher für die Vektordaten Mitglied der der abgeleiteten Klasse zugeordnet auslaufen.

Destructor ist die Memberfunktion der Klasse, dessen Name ist der gleiche Name des Klassennamen und es wird durch die Tilde-Zeichen (~) vorangestellt. Destructor wird verwendet, um das Objekt der Klasse zu zerstören, wenn das Objekt Gültigkeitsbereich verlässt, oder Sie können sagen, dass alles sauber aus Klasse Zerstörung sind in destructor getan werden. Alle Speicher während des Baus des Objekts in der Klasse zugewiesen wird, wird auch zerstört (oder die Speicherfreigabe), wenn das Objekt geht out of scope.

Weitere Details mit Beispiel auf BoundsCheck

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top