Exception im Konstruktor - was ist mit Konstruktoren in Initialisierungsliste?



  • Angenommen ich habe eine Klasse A, die von B und C ableitet.
    A ruf die Konstruktoren von B und C in der Initialisierungsliste auf und dann wirft A im Konstruktor eine Exception.

    Was passiert dann mit B und C? Deren Konstruktoren werden ja aufgerufen, aber die Destruktor nicht mehr. Müsste man das speziell handeln, weil die Objekte so im Speicher bleiben, oder werden die doch irgendwann noch irgendwie gelöscht?


  • Mod

    Yarrow schrieb:

    Was passiert dann mit B und C? Deren Konstruktoren werden ja aufgerufen, aber die Destruktor nicht mehr.

    Zum Glück ist dem nicht so, hier darsft du auf Compilermagie vertrauen. Jedes vollständig konstruierte Subobjekt wird (in umgekehrter Reihenfolge der Konstruktion) auch wieder zerstört, falls die Konstruktion des gesamten Objektes doch noch fehlschlägt. Das gleiche Problem ergibt sich im Fall von Arrays.



  • Aber ich hab in der Klasse den Destruktor erstellt und lasse da extra eine Meldung ausgeben, die kommt aber nicht mehr. 😕



  • struct B 
    {
    	~B() { std::cout << "~B() "; }
    };
    
    struct C
    {
    	~C() { std::cout << "~C() "; }
    };
    
    struct A: B, C
    { 
    	A(): B(), C() { throw "Error!"; }
    
    	~A() { std::cout << "~A()"; }
    };
    
    int main()
    {
    	try	{ A a; }
    	catch (const char* message)
    	{ std::cout << message;	}
    }
    

    Ausgabe:

    ~C() ~B() Error!
    

    Genau, wie erwartet. Es gibt jetzt zwei Möglichkeiten:
    1. Du machst was ganz anderes falsch.
    2. Du benutzt einen veralteten Compiler.

    Gruß
    Don06



  • Achsoo.. Ich hatte kein try-catch, deshalb hat's nicht funktioniert.

    Dankeschön..



  • camper schrieb:

    Yarrow schrieb:

    Was passiert dann mit B und C? Deren Konstruktoren werden ja aufgerufen, aber die Destruktor nicht mehr.

    Zum Glück ist dem nicht so, hier darsft du auf Compilermagie vertrauen. Jedes vollständig konstruierte Subobjekt wird (in umgekehrter Reihenfolge der Konstruktion) auch wieder zerstört, falls die Konstruktion des gesamten Objektes doch noch fehlschlägt. Das gleiche Problem ergibt sich im Fall von Arrays.

    Mal nachgefragt: Ist es dafür nicht unerheblich, ob die Objekte in der Initialisierungsliste initialisiert wurden oder ob im Konstruktorrumpf eine Zuweisung erfolgte?

    Wird nicht in jedem Fall bei einem throw im Konstruktor die Destruktoren sämtlicher Klassenattribute aufgerufen?



  • Zelt schrieb:

    Mal nachgefragt: Ist es dafür nicht unerheblich, ob die Objekte in der Initialisierungsliste initialisiert wurden oder ob im Konstruktorrumpf eine Zuweisung erfolgte?

    Die Objekte werden immer in der Initialisierungsliste initialisiert. Wenn du sie nicht in die Initialisierungsliste schreibst, wird implizit der Default Ctor aufgerufen.

    Daraus folgt: sobald der Koerper des Ctors ausgefuehrt wird, sind alle member vollstaendig konstruiert. Und somit werden sie im Falle einer Exception auch vollstaendig destruiert.

    Selbes gilt wenn in der Initialisierungsliste eine Exception fliegt: alle bis zum zeitpunkt des Auftretens der Exception vollstaendig konstruierte Objekte werden auch korrekt wieder geloescht.

    Oder wie camper so schoen gesagt hat:
    Jedes vollständig konstruierte Subobjekt wird (in umgekehrter Reihenfolge der Konstruktion) auch wieder zerstört



  • Shade Of Mine schrieb:

    Zelt schrieb:

    Mal nachgefragt: Ist es dafür nicht unerheblich, ob die Objekte in der Initialisierungsliste initialisiert wurden oder ob im Konstruktorrumpf eine Zuweisung erfolgte?

    Die Objekte werden immer in der Initialisierungsliste initialisiert. Wenn du sie nicht in die Initialisierungsliste schreibst, wird implizit der Default Ctor aufgerufen.

    Daraus folgt: sobald der Koerper des Ctors ausgefuehrt wird, sind alle member vollstaendig konstruiert. Und somit werden sie im Falle einer Exception auch vollstaendig destruiert.

    Selbes gilt wenn in der Initialisierungsliste eine Exception fliegt: alle bis zum zeitpunkt des Auftretens der Exception vollstaendig konstruierte Objekte werden auch korrekt wieder geloescht.

    Oder wie camper so schoen gesagt hat:
    Jedes vollständig konstruierte Subobjekt wird (in umgekehrter Reihenfolge der Konstruktion) auch wieder zerstört

    Also liegt der einzige Vorteil der Initialisierungsliste darin, dass sie schneller ist, als die Zuweisungen im Konstruktor-Rumpf, da ggfs. für komplexe Objekte kein Standard-ctor aufgerufen wird?



  • Zelt schrieb:

    Also liegt der einzige Vorteil der Initialisierungsliste darin, dass sie schneller ist, als die Zuweisungen im Konstruktor-Rumpf, da ggfs. für komplexe Objekte kein Standard-ctor aufgerufen wird?

    Ich wuerde nicht von Vorteil oder so sprechen. Die Initialisierungsliste initialisiert. Wenn du ein Objekt selber initialisieren willst (oder es musst: weil es const ist oder eine referenz) dann musst du dies in der Initialisierungsliste tun - andernfalls wird der Standard Ctor aufgerufen.

    Und Standard Ctor Aufruf und nachher eine Zuweisung machen - das ist natuerlich viel langsamer als direkt den richtigen Ctor aufzurufen. Aber wie gesagt: Initialisierungen muessen in der Initialisierungsliste stehen, die koennen garnicht woanders stehen.

    Deshalb stellt sich die Frage mit Vorteil/Nachteil nicht. Weil es garnicht anders geht.



  • Okay, danke


Anmelden zum Antworten