Destructor und delete



  • Guten Tag,
    ich habe ein Problem mit dem Destruktor.

    Eigentlich hatte ich vor in Klassen allokierte variablen am ende durch den Destruktor wieder freizugeben, jedoch führt meine momentane implementierung mit operation overload dazu, dass es mehrfach freigegeben wird.

    Ich habe das problem mal vereinfacht hier in einen code schnipsel gegossen:

    #include <iostream>
    using namespace std;
    
    class test
    { 
      int* value;
      public:
      test() {value= new int;*value=1;};
      ~test() {delete value;};
    
      void operator = (test b) {*value=*(b.value);};
    };
    
    int main(void)
    {
      test a,b;
      a=b;
      return 0;
    }
    

    Ich würde dabei gerne verhindern, dass der "a=b" aufruf den Destruktor ausführt und es so natürlich zu fehlern kommt.



  • dajohnny schrieb:

    Ich würde dabei gerne verhindern, dass der "a=b" aufruf den Destruktor ausführt und es so natürlich zu fehlern kommt.

    1. Beim Zuweisungsoperator eine const-Referenz als Parameter übergeben
    2. Kopierkonstruktor implementieren, der fehlt auch noch



  • Edit: Ah, falsch gelesen. Sry.



  • Wie Bashar sagte, den Kopierkonstruktor implementieren und bei beiden den Parameter als const-Referenz übergeben.



  • Dein Problem ist, etwas genauer beschrieben, das

    void operator = (test b) {*value=*(b.value);};
    

    den copy-ctor aufruft - da du denn hier aber nicht implementiert hast, macht der einfach ne flache kopie vom zeiger. Am Ende von operator= wird dieses wieder zerstört (erstes delete). Sobald du das objekt selbst zerstört, kommt auf denselben zeiger das zweite delete.
    Die Lösung wurde schon gesagt: const-Referenz und richtigen copy-ctor schreiben.



  • test a,b;
    

    Hier wurden sowohl a.value als auch b.value alloziiert

    a=b;
    

    hier wird zunächst b kopiert, da der operator= ja eine temporäre Kopie des Objektes erwartet. Dabei zeigt b und die Kopie auf das selbe b.value. Wird das temporäre Objekt wieder gelöscht, wird b.value frei gegeben. Unglücklicherweise zeigt aber b noch darauf. Wenn main verlassen wird, wird der Destruktor von b aufgerufen, welcher b.value ein zweites mal frei gibt.

    In der Regel ist es notwendig, sowohl den Kopierkonstruktor als auch den Zuweisungsoperator korrekt zu implementieren oder außer Kraft zu setzen, wenn so mit Zeigern umgegangen wird.

    Das würde dann in etwa so aussehen (mit ein paar anderen kleinen Korrekturen):

    class test
    {
        int* value;
      public:
        test() { value = new int; *value=1; }
        test(const test& t) { value = new int; *value = *t.value; }
        ~test() {delete value; }
    
        test& operator = (const test& b) { *value=*b.value; return *this; }
    };
    
    int main(int argc, char* argv[])
    {
      test a,b;
      a=b;
    }
    

    Wobei man sich natürlich fragen kann, welchen Sinn das macht, die Member als Zeiger anzulegen. Aber Du hast ja gesagt, dass das nur ein vereinfachtes Beispiel ist. Da ist es natürlich valide.



  • dajohnny schrieb:

    ich habe ein Problem mit dem Destruktor.

    Nee, so würde ich das nicht sagen. Dein Problem ist die Verletzung der 3er-Regel.

    dajohnny schrieb:

    class test
    { 
      int* value;
      public:
      test() {value= new int;*value=1;};
      ~test() {delete value;};
    
      void operator = (test b) {*value=*(b.value);};
    };
    

    Mal davon abgesehen, dass es hier natürlich absolut keinen Sinn macht, value als Zeiger anzulegen: Ja, hier hast Du die 3er-Regel verletzt. Insbesondere fehlt hier der Kopierkonstruktor. Und b bei operator= sollte eine Referenz-auf-const sein.

    dajohnny schrieb:

    Ich würde dabei gerne verhindern, dass der "a=b" aufruf den Destruktor ausführt

    Das tut er doch gar nicht!

    dajohnny schrieb:

    und es so natürlich zu fehlern kommt.

    Du verletzt ja auch die 3er-Regel.


Anmelden zum Antworten