Wie kann ich verhindern, dass ein Konstruktor eine Ausnahme auslöst?
Im folgenden Beispiel erstelle ich eine Month () -Klasse, für die die legalen Werte der int month_
-Eigenschaft im Bereich von 1 bis 12 liegen. Ich instanziiere Dezember, oder dec
, mit Ganzzahlwert 13. Die Ausnahme wird geworfen, wie es sein sollte, aber das Objekt wird immer noch erstellt . Der Destruktor wird dann aufgerufen.
Wie kann ich die Erstellung einer Klasseninstanz bei einer ausgelösten Ausnahme abbrechen?
AUSGABE
%Vor%Minimales, vollständiges und überprüfbares Beispiel
%Vor%Wie kann ich die Erstellung einer Klasseninstanz bei einer ausgelösten Ausnahme abbrechen?
Nun, Sie werfen eine Ausnahme im Konstruktor. Aber es gibt einen Haken: Fange es nicht !
Wenn Sie es fangen, wäre es so, als wäre die Ausnahme nie passiert. Du hast es gefangen, also geht es nicht mehr in den Call-Stack. Das Objekt wird also erstellt, da der Konstruktor für niemanden eine Ausnahme ausgelöst hat.
Wenn Sie die catch
-Klausel aus dem Konstruktor entfernen, erhalten Sie wahrscheinlich Folgendes:
Hier hat der Konstruktor eine Exception geworfen, und diesmal ist der Aufruf-Stack außerhalb des Konstruktors gegangen, weil niemand ihn im Konstruktor abgefangen hat. Es geht dann zu makeMonths
, wo es auch nicht abgefangen wird, und dann zu main
, wo es auch nicht abgefangen wird, und so wird das Programm abnormal beendet.
Das Auslösen einer Ausnahme in einem Konstruktor sollte standardmäßig verhindern, dass der Destruktor jemals aufgerufen wird. Sie fangen jedoch die Ausnahme und behandeln sie.
Sie könnten eine neue Exception in Ihren Catch schreiben, die dann außerhalb dieses Bereichs angezeigt wird, so dass der Destruktor nicht aufgerufen wird.
Wie kann ich die Erstellung einer Klasseninstanz bei einer ausgelösten Ausnahme abbrechen?
Sie werfen die Ausnahme einfach (erneut), anstatt sie zu fangen, würde ich empfehlen, eine std::invalid_argument
oder std::out_of_range
Ausnahme:
Ihre erstellte Instanz von Month
wird ordnungsgemäß mit dem Stapelabwicklungsmechanismus verworfen. Es wird niemals eine Instanz erstellt, daher wird der Destruktor überhaupt nicht aufgerufen.
Sehen Sie sich ein Live-Beispiel an.
Um die Ausnahme informativer zu machen, könnten Sie etwas in diesen Zeilen verwenden:
%Vor%Auch wenn Sie die Member-Variable im Konstruktor nicht initialisieren möchten (wie ich es meistens tue)
Sie können nur einen Lambda-Ausdruck für den Gültigkeitsprüfcode einführen:
%Vor%Sie sollten eine Exception aus dem Konstruktor auslösen und sie in einem anderen Code als dem Konstruktor abfangen, z. B. wo die Objekterstellung versucht wird.
Wenn ein Konstruktor beendet wird, indem eine Ausnahme ausgelöst wird, wird der mit dem Objekt selbst verbundene Speicher bereinigt - es gibt keinen Speicherverlust.
Wenn ein Konstruktor eine Ausnahme auslöst, wird der Destruktor des Objekts nicht ausgeführt.
Sie können das Factory-Methodenmuster verwenden, um zu vermeiden, dass der Konstruktor aufgerufen wird, wenn die Eingabe nicht gültig ist.
Gist:
Erstellen Sie eine static
-Methode namens .New()
oder etwas.
Externe Entitäten rufen .New()
anstelle des Konstruktors auf.
.New()
validiert die Eingabe.
Wenn die Eingabe gut ist, ruft sie den Konstruktor auf und gibt das Ergebnis zurück.
Andernfalls wird eine Ausnahme ausgelöst. Oder Sie können null
zurückgeben oder einen nicht null
Standardwert zurückgeben.
Sie müssen eine Exception zum Beispiel an main senden, Nachricht über Konstruktor sollte in Block try
sein.
Damit...
2. Objekte werden erstellt und wenn 3. Objekt erstellt wird, Ausnahme throw 100
und wird in main behandelt. Es ist eines von vielen Möglichkeiten, denke ich.
AUSGABE:
%Vor%Tags und Links c++ exception-handling c++11 constructor try-catch