Verhindern, dass der Konstruktor ein Objekt erstellt, wenn eine Ausnahme ausgelöst wird

7

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%     
kmiklas 30.06.2017, 19:21
quelle

6 Antworten

15
  

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:

%Vor%

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.

    
Rakete1111 30.06.2017 19:28
quelle
10

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.

    
Software2 30.06.2017 19:27
quelle
4
  

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:

%Vor%

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%

Live-Demo

    
user8238559 30.06.2017 19:35
quelle
1

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.

Von der iso / cpp-Quelle 1

  

Wenn ein Konstruktor eine Ausnahme auslöst, wird der Destruktor des Objekts nicht ausgeführt.

Von der iso / cpp-Quelle 2

    
cse 30.06.2017 20:57
quelle
1

Sie können das Factory-Methodenmuster verwenden, um zu vermeiden, dass der Konstruktor aufgerufen wird, wenn die Eingabe nicht gültig ist.

Gist:

  1. Erstellen Sie eine static -Methode namens .New() oder etwas.

  2. Externe Entitäten rufen .New() anstelle des Konstruktors auf.

  3. .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.

%Vor%     
Nat 01.07.2017 01:55
quelle
1

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.

%Vor%

AUSGABE:

%Vor%     
21koizyd 30.06.2017 19:31
quelle