2015-01-13 6 views
48

Ich bin mir nicht sicher, ob dies ein Problem mit dem Compiler ist oder ob ich etwas falsch mache. Ich verwende den Visual Studio 2013-Compiler.Konstruktor als Funktion try Block - Ausnahme bricht Programm ab

Ich habe eine Klasse, wo ich erhebliche Menge an Ressourcen in meinem Konstruktor Initialisierungsliste erwerben müssen, von denen die meisten eine Ausnahme auslösen können. Ich habe die Member-Initialisierer-Liste in einem Funktionstry-Block eingepackt und dort die Ausnahme abgefangen. Aber mein Programm bricht immer noch ab, obwohl die catch-Klausel die Ausnahme nicht erneut auslöst. Ich darf den eigentlichen Code nicht posten. Also habe ich das Problem mit diesem äquivalenten Demo-Code reproduziert. Kann mir bitte jemand helfen?

#include <iostream> 
using namespace std; 
class A{ 
public: 
    A() try : i{ 0 }{ throw 5; } 
    catch (...){ cout << "Exception" << endl; } 
private: 
    int i; 
}; 


int main(){ 
    A obj; 
} 

Bei der Ausführung dieses Codes bekomme ich einen Windows-Alarm "abort() wurde aufgerufen". Ich nehme an, dass das System dies als eine nicht abgefangene Ausnahme behandelt und terminate() aufruft.

Auf der anderen Seite, wenn ich die Konstruktion des Objekts in main() in einem try-catch-Block wickeln, dann wird die Ausnahme richtig gefangen und das Programm wird normal beendet.

Kann mir bitte jemand sagen, ob ich hier etwas falsch mache?

+4

Blick auf http://www.gotw.ca/gotw/066.htm für eine Diskussion über dieses Problem –

+0

Vielen Dank Jan Herrmann. Es ist offensichtlich sehr sinnvoll, wenn der Standard sagt, wenn eine Ausnahme nicht erneut ausgelöst wird oder wenn eine neue Eszeption nicht aus der Funktion try block des Konstruktors geworfen wird, wird sie am Ende des catch-Blocks automatisch erneut ausgelöst. Das macht jetzt vollkommen Sinn. Vielleicht, wie vorgeschlagen, Pimpl Idiom ist, was ich anfangen sollte zu verwenden. Nochmals vielen Dank. – Madhusudhan

+20

Zusätzliche Punkte für * "Ich darf den eigentlichen Code nicht posten. Also habe ich das Problem mit diesem äquivalenten Democode reproduziert. "* Sie haben eine sehr gute [MCVE] erstellt (https://stackoverflow.com/help/mcve). – 5gon12eder

Antwort

30

Es gibt eine relevante GOTW

http://gotw.ca/gotw/066.htm

Grundsätzlich auch wenn Sie nicht in Ihrem Catch-Block werfen Sie, wird die Ausnahme automatisch

Wenn der Handler Körper enthalten ist die Aussage "erneut ausgelöst werden werfen;" dann würde der Catch Block offensichtlich die Ausnahme erneut auslösen, die A :: A() oder B :: B() ausgesendet hatte. Was weniger offensichtlich, aber klar im Standard angegeben ist, ist , wenn der catch-Block nicht wirft (entweder die ursprüngliche Ausnahme erneut auslösen oder etwas Neues werfen), und die Steuerung erreicht das Ende des catch-Block eines Konstruktors oder Destruktors , dann wird die ursprüngliche Ausnahme automatisch erneut ausgelöst.

+0

Diese Seite ist eine wirklich gute Lektüre. Wusste nicht die Funktion-Try-Block-Syntax existierte vor dieser Frage; habe viel von diesem Link gelernt! Insbesondere gibt es die fantastische Analogie: "Wenn die Konstruktion eines Basis- oder Mitgliedsobjekts fehlschlägt, muss das gesamte Objekt * versagen ... es gibt keine Möglichkeit für einen Menschen, [geboren zu werden], wenn irgendwelche seiner lebenswichtigen Organe niemals gebildet würden". – OJFord

+0

die ganze gotw Website ist eine Goldmine für jeden C++ Entwickler! Zusammen mit Bjarne Website, Paraschift, cppreference und cplusplus –

+0

Ich habe genau das in den 48 Minuten seit meinem obigen Kommentar entdeckt! Eine Schande zuletzt war 1/1/08. – OJFord

22

Dies ist ein normales Verhalten nach the cppreference.com documentation for function-try blocks: eine sogenannte Funktion-try-Block auf einem Konstruktor oder Destruktor muss von seinem Fang-Klausel werfen oder sonst gibt es eine implizite rethrow nach dem Fang-Klausel.

Das macht durchaus Sinn: das Objekt A ist nicht richtig aufgebaut und daher nicht in einem gebrauchstauglichen Zustand: es muss eine Ausnahme auslösen. Sie müssen sicherstellen, dass die Konstruktion an der Stelle erfolgreich war, an der das Objekt erstellt wurde, d. H. Im Fall Ihres Beispiels in main().

+4

Upvoting, weil diese Antwort eine menschlichere lesbare Antwort als die zitierten Standarden hat. Zum OP: Ihr Problem besteht darin, dass eines oder mehrere Ihrer Mitglieder sich in einem unkonstruierten Zustand befinden (da Sie nicht wissen, welcher Mitgliedsaufbau war, wissen Sie nicht, welche Mitglieder vollständig konstruiert wurden). Daher ist Ihre Klasse nicht vollständig aufgebaut. Wenn es erneut gestartet wird, ist sichergestellt, dass Sie diese Instanz nicht verwenden können. Mitglieder, die vollständig gebaut wurden, werden angemessen zerstört. –

9

Ausnahme kann nicht im Konstruktor function-try-block abgefangen werden.

n3376 15,2/15

Die aktuell behandelte Ausnahme erneut ausgelöst wird, wenn die Steuerung das Ende eines Handlers der Funktion-try-Block von einem Konstruktor oder destructor erreicht.

Sie sollten es in Objekt Erstellungsort fangen.