Destruktor wird doppelt ausgeführt



  • Hallo, mein Problem ist, das der Destruktor, nachdem ich ihn selbst aufgerufen habe, er zum Ende der Laufzeit nochmals aufgerufen wird.

    Klasse "Animal" Header:

    #ifndef ANIMAL_H
    #define ANIMAL_H
    
    #include <iostream>
    #include <string>
    
    class animal
    {
    public:
        animal(); //Standartkonstruktor
        ~animal(); //Destruktor
        animal(int p_i); //Konstruktor
    
    protected:
    
        int i;
    };
    
    #endif // ANIMAL_H
    

    Klasse "Animal" Source:

    #include "animal.h"
    
    animal::animal()  //Standartkonstruktor
    {
        std::cout << "ANIMAL KONSTRUKTOR" << std::endl;
    }
    
    animal::~animal() // Destruktor
    {
        std::cout << "ANIMAL DESTRUKTOR" << std::endl;
    }
    
    animal::animal(int p_i) //Konstruktor
    {
        std::cout << "ANIMAL KONSTRUKTOR" << std::endl;
        this->i = p_i;
    }
    
    

    Main Source:

    #include <stdio.h>
    #include <time.h>
    
    #include <animal.h>
    
    int main()
    {
        animal hirsch(2); //Aufruf des Konstruktors
        hirsch.~animal(); //Aufruf des Destruktors
        return 0;
    }
    

    Die Ausgabe in der Konsole lautet:

    ANIMAL KONSTRUKTOR
    ANIMAL DESTRUKTOR
    ANIMAL DESTRUKTOR
    Bet~otigen Sie die <RETURN> Taste, ...
    

    Ich würde das gerne abstellen, da es ein und derselbe Speicherbereich ist, der durch den Destruktor freigegeben wird, vielleicht hat ja jemand eine Lösung für mich.

    Mit freundlichen Grüßen
    Flip-Flop_Träger



  • int main()
    {
        {
            animal hirsch(2); //Aufruf des Konstruktors
        } //Aufruf des Destruktors
        return 0;
    }
    


  • @Flip-Flop_Träger ganz einfach, den Destruktor nicht selbst aufrufen. Alle Objekte die auf dem Stack liegen, werden am Ende des Gültigkeitsbereich aufgeräumt, in dem der Kompiler dafür sorgt das der Destruktor aufgerufen wird.



  • @Flip-Flop_Träger sagte in Destruktor wird doppelt ausgeführt:

    animal::animal(int p_i) //Konstruktor
    {
        std::cout << "ANIMAL KONSTRUKTOR" << std::endl;
        this->i = p_i;
    }
    
    animal::animal(int i) : i{ i } {}
    


  • Danke für eure Antworten,

    @titan99_ und @Schlangenmensch, ich nehme eure Anmerkung dankbar an und werde ich mich daran halten den Destruktor nicht selbst aufzurufen, sondern das dem Compiler zu überlassen.

    @titan99_ sagte in Destruktor wird doppelt ausgeführt:

    int main()
    {
        {
            animal hirsch(2); //Aufruf des Konstruktors
        } //Aufruf des Destruktors
        return 0;
    }
    

    Danke auch an @Swordfish für seine Antwort, eine Initialisierungsliste ist nur leider nicht die Lösung um das doppelte Ausführen des Destruktors zu verhindern.
    Ich mag Initialisierungslisten nicht besonders, mir persönlich geht dabei die einfache Lesbarkeit des Codes verloren.

    Mit freundlichen Grüßen

    Flip-Flop_Träger

    #Edit 1: Code Zitiert
    #Edit 2: Edit bemerkung eingefügt


  • Mod

    @Flip-Flop_Träger sagte in Destruktor wird doppelt ausgeführt:

    Danke auch an @Swordfish für seine Antwort, eine Initialisierungsliste ist nur leider nicht die Lösung um das doppelte Ausführen des Destruktors zu verhindern.
    Ich mag Initialisierungslisten nicht besonders, mir persönlich geht dabei die einfache Lesbarkeit des Codes verloren.

    Das hat Swordfish gezeigt, weil es in jeder Hinsicht die bessere Lösung ist. Um Initialisierungslisten wirst du nicht herum kommen. Nicht nur, dass sie viele Vorteile haben, viele Dinge sind ohne sie gar nicht möglich. Daher gewöhn dich lieber sofort dran.



  • @Flip-Flop_Träger sagte in Destruktor wird doppelt ausgeführt:

    mir persönlich geht dabei die einfache Lesbarkeit des Codes verloren.

    animal::animal(int foo, int bar, int qux = 42)
    : foo { foo },
      bar { bar },
      qux { qux }
    {}
    

    Kann ich nicht so wirklich nachvollziehen.



  • @Swordfish sagte in Destruktor wird doppelt ausgeführt:

    @Flip-Flop_Träger sagte in Destruktor wird doppelt ausgeführt:

    mir persönlich geht dabei die einfache Lesbarkeit des Codes verloren.

    animal::animal(int foo, int bar, int qux = 42)
    : foo { foo },
      bar { bar },
      qux { qux }
    {}
    

    Kann ich nicht so wirklich nachvollziehen.

    ... Mal ganz davon abgesehen, dass auch ein funktionaler Unterschied besteht (Initialisierung v.s. Zuweisung). Ich würde ebenfalls empfehlen, die Konstruktor Initialisierungsliste zu verwenden, und dabei auch empfehlenswert: In der selben Reihenfolge, wie die Member innerhalb der Klasse definiert sind. Sonst könnte da auch Verwechslung aufkommen in Bezug auf die Initialisierungsreihenfolge.

    Bonus Tipp: Als Daumenregel alle Konstruktoren, welche sich mit einem einzigen Argument aufrufen lassen, sollten als explicit definiert werden, also:

    explicit animal(int p_i); //Konstruktor