2010-03-17 8 views
22

Ist das Folgende in C++ klar definiert oder nicht? Ich bin gezwungen, Ausnahmen in Rückgabecodes zu konvertieren (die betreffende API wird von vielen C-Benutzern verwendet, daher muss ich sicherstellen, dass alle C++ - Ausnahmen abgefangen werden, bevor die Kontrolle an den Aufrufer zurückgegeben wird).Wird eine Ausnahme in einem verschachtelten "Versuch" erneut ausgelöst?

enum ErrorCode {…}; 
ErrorCode dispatcher() { 
    try { 
     throw; 
    } 
    catch (std::bad_alloc&) { 
     return ErrorCode_OutOfMemory; 
    } 
    catch (std::logic_error&) { 
     return ErrorCode_LogicError; 
    } 
    catch (myownstdexcderivedclass&) { 
     return ErrorCode_42; 
    } 
    catch(...) { 
     return ErrorCode_UnknownWeWillAllDie; 
    } 
} 

ErrorCode apifunc() { 
    try { 
     // foo() might throw anything 
     foo(); 
    } 
    catch(...) { 
     // dispatcher rethrows the exception and does fine-grained handling 
     return dispatcher(); 
    } 
    return ErrorCode_Fine; 
} 

ErrorCode apifunc2() { 
    try { 
     // bar() might throw anything 
     bar(); 
    } 
    catch(...) { 
     return dispatcher(); 
    } 
    return ErrorCode_Fine; 
} 

Ich hoffe, die Probe zeigt meine Absicht. Meine Vermutung ist, dass dies ein undefiniertes Verhalten ist, aber ich bin mir nicht sicher. Bitte geben Sie ggf. Zitate aus dem Standard an. Alternative Ansätze werden ebenfalls geschätzt.

Danke!

+1

Ich erinnere mich daran, diesen Ansatz zu betrachten, um Code-Duplizierung zu reduzieren, die von verschiedenen try/catch-Blöcken herrührt, aber ich implementierte es. Was lässt Sie glauben, dass es illegal sein könnte? –

+0

Ich habe das auch schon benutzt, es ist eine großartige Technik – iain

+2

@jdv - Ich fühlte mich ein wenig unbehaglich, wenn ich innerhalb eines try Blocks, der in einer catch-Klausel (und sogar in einem anderen Stack-Frame) verschachtelt war, erneut austrug. Es sah einfach ein bisschen zu schön aus, also wollte ich auf der sicheren Seite sein. –

Antwort

12

Das ist in Ordnung. Die Ausnahme ist aktiv, bis sie abgefangen wird und inaktiv wird. Aber es lebt, bis der Umfang des Handlers endet. Vom Standard, Hervorhebung von mir:

§ 15.1/4: Der Speicher für die temporäre Kopie der Ausnahme in einer unbestimmten Weise zugewiesen wird geworfen, mit Ausnahme des in 3.7.4.1 festgestellt. Das temporäre Objekt bleibt bestehen, solange ein Handler für diese Ausnahme ausgeführt wird.

Das heißt:

catch(...) 
{ // <-- 

    /* ... */ 

} // <-- 

Zwischen diesen Pfeilen können Sie die Ausnahme erneut werfen. Nur wenn der Handler-Bereich endet, hört die Ausnahme auf zu existieren.

Denken Sie daran, wenn Sie dispatch ohne eine aktive Ausnahme aufrufen, wird terminate aufgerufen werden. Wenn dispatch eine Exception in 1 auslöst, wenn es sich um Handler handelt, wird die Exception beginnen sich zu verbreiten. Weitere Informationen unter a related question.

+0

Es wäre in Ordnung, diese Approuch innerhalb einer Methode zu verwenden, die in einem Konstruktor aufgerufen wird? (g ++) – agodinhost

2

Seit dispatcher im Catch-Block throw aufgerufen wird Ausnahme erneut auslösen. Wenn Sie dispatcher außerhalb des Catch-Blocks anrufen, wird terminate() aufgerufen (gemäß 15.1/8). Es gibt auf keinen Fall ein undefiniertes Verhalten.

Verwandte Themen