2013-04-19 2 views
9

Ich stieß auf ein interessantes Szenario mit Flusskontrolle während der Arbeit an meiner Sprache. Was passiert, wenn während der Verarbeitung einer break-Anweisung eine Ausnahme ausgelöst wird? GCC scheint zu glauben, dass der Break-Flow verloren ist, aber der Standard scheint etwas still darüber zu sein, was passieren sollte.Soll break/continue/return von einer Ausnahme unterbrochen werden?

Zum Beispiel, was sollte das folgende Programm tatsächlich tun?

#include <iostream> 
using namespace std; 

struct maybe_fail { 
    bool fail; 
    ~maybe_fail() { 
     if(fail) 
      throw 1; 
    } 
}; 

int main() { 
    for(int i=0; i < 6; ++i) { 
     cout << "Loop: " << i << endl; 

     try { 
      maybe_fail mf; 
      mf.fail = i % 2; 
      if(i == 3) 
       break; 

     } catch(int) { 
      cout << "Caught" << endl; 
     } 
    } 
    return 0; 
} 

Beachten Sie, dass ein return auch blockiert werden, ebenso wie ein continue (fügt Ausgang nach dem Fang, das zu sehen). Versuch, goto außerhalb des Blocks wird auch gefangen werden.

Was ist der richtige Durchfluss? Der Standard scheint dies nicht zu berücksichtigen: Abschnitt 6.6 zu Sprunganweisungen erwähnt nichts und auch Abschnitt 15 zur Ausnahmebehandlung nicht. Ich verstehe, dass Ausnahmen in Destruktoren in schrecklich schlechter Form sind, aber wenn Sie etwas wie BOOST_SCOPE_EXIT für Defer-Anweisungen verwenden, könnte dieses Verhalten sehr wichtig werden.

Vielleicht ist der gleiche Ablauf in Java und Python von Interesse, so scheint zumindest eine gewisse Konsistenz in den Imperativsprachen zu bestehen.

+0

Ihre Frage scheint den Rat in den C++ - FAQ zu rechtfertigen: http://www.parashift.com/c++faq-lite/dtors-shouldnt-throw.html Grundsätzlich, werfen Sie keine Ausnahmen in Destruktoren. Diese Frage in den FAQ lautete, wie 'terminate()' aufgerufen wird, wenn Sie sich in einer "double-exception-handling" -Situation befinden, aber Ihr Beispiel scheint den Ratschlag fortzusetzen, dass es einfach schlecht ist. –

+1

@Kevin, dieser Rat würde sich dann auf jede "verzögernde" Anweisung in jeder Sprache erstrecken (einschließlich BOOST_SCOPE_EXIT für C++). –

+0

Wie sonst würden Sie das Verhalten interpretieren? wirf die Ausnahme in den Destruktor, und was dann? – bdwain

Antwort

4

Dies wird in 15,1 Auslösen einer Ausnahme behandelt:

2 Wenn eine Ausnahme ausgelöst wird, die Steuerung an den nächsten Handler mit einem passenden Typ übertragen (15,3); "nächstgelegen" bedeutet den Handler, für den die zusammengesetzte Anweisung oder der ctor-Initialisierer, der dem try-Schlüsselwort folgt, zuletzt vom Thread der Steuerung eingegeben und noch nicht verlassen wurde.

Sobald die Steuerung an den Ausnahmebehandler übergeben wurde, wird sie von dort fortgesetzt. Es gibt keinen Mechanismus, um sich daran zu erinnern, dass der Code in der Mitte eines break war und dann irgendwie wieder aufgenommen wird, nachdem die Ausnahme behandelt wurde.

+0

Ich bin mir nicht sicher, dass das genug Klarheit ist. Beachten Sie, dass Abschnitt 6.6 erfordert, dass die Sprunganweisungen wie angegeben ausgeführt werden, und erwähnt keine Unterbrechung dieses Flusses. Das heißt, ich denke, dass die Anforderung, die Sie angeben, und die Sprunganforderungen in Konflikt stehen. –

+0

@ edA-qamort-ora-y Würde ein Verweis auf den Standard für die Wirkung von "Destruktoren * genannt * bevor * der Sprung stattgefunden hat" diese Frage beantworten? –

+0

@ edA-qamort-ora-y: Um ehrlich zu sein, nachdem ich auf 6.6 (besonders den zweiten Absatz) geschaut habe, und ich bin mir nicht sicher, ob ich die Mehrdeutigkeit sehe. – NPE

0

Angesichts der spezifischen Formulierung im Stadnad, werde ich sagen, dass es mehrdeutig ist. Der Text reicht nicht aus, um die beabsichtigten Ströme dieser Situationen zu identifizieren. Es ist durchaus möglich, dass die Konvention, die wir jetzt haben, nur zufällig ist, weil Compiler geschrieben werden.

Siehe mein Blog-Thema How to catch a "return" statement.