2012-07-02 4 views

Antwort

13

Diese Seite ist dumm und lehrt schlechtes Design.

Wenn Sie int oder char* werfen, dann werden Sie es fangen müssen int oder char* nur verwenden. Sie können es mit const qualifizieren.

Wenn Sie std::runtime_error werfen, können Sie es mit std::runtime_error const & oder seiner Basisklasse std::exception const & abfangen.

Was ist also gut daran?

Die gute daran ist, dass, wenn Sie eine Ausnahme mit einer Klasse werfen, die letztlich von std::exception abgeleitet wird, dann können Sie nur ONE catch Block schreiben, die die Ausnahme als std::exception const&, unabhängig von which derived class verwendet wird akzeptiert Ausnahme zu werfen. Hier

ist ein Beispiel:

void f(A & a) 
{ 
    if (!check_arg(a)) 
    { 
      throw std::invalid_argument("invalid argument"); 
    } 
    else if (!check_size(a)) 
    { 
      throw std::length_error("invalid length");    
    } 

    //code 
    if(someCondition) 
    { 
      //assume your_own_defined_exception's ultimate base is std::exception 
      throw your_own_defined_exception("condition unsatisfied");       
    } 
    //... 

} 

Jetzt ist der interessante Teil:

try 
{ 
     f(a); //it can throw exception of at least 3 types! 
} 
catch(std::exception const &e) //all types can be caught by just one catch! 
{ 
    //handle this case 
} 

Das Gute ist, dass Sie nicht erforderlich dreicatch Blöcke zu schreiben, nur weil f() werfen könnte drei verschiedene Arten von Ausnahmen. Sie können schreiben mehr als eine catch, um sie anders zu behandeln, wenn das in irgendeiner Weise davon profitiert. Aber der Punkt, der hier zu beachten ist: das ist nicht eine Anforderung!

Kurz gesagt, können Sie die Klassenhierarchie nutzen.

+0

Grundsätzlich ermöglicht es natürlich Vererbung, das Design der Fehlerbehandlung zu vereinfachen. Ziemlich elegant. Wenn ich meine eigene Ausnahmeklasse definiere und es so mache, kann ich die gleichen Ergebnisse erzielen, ja? –

+3

@StevenLu Wenn Sie eine eigene Ausnahmeklasse ableiten, erfinden Sie das Rad neu und brechen möglicherweise Code, der davon abhängt, dass std :: exception abgefangen wird. Während dies für Ihre persönlichen Projekte in Ordnung sein kann, ist es schwierig, Ihren Code an andere zu verteilen. Der Standardansatz besteht darin, eine anwendungsspezifische Ausnahmehierarchie mit der Unterklasse "std :: exception" zu haben. Zum Beispiel sind alle Ihre Ausnahmen Unterklassen von 'StevenLuException', was eine Unterklasse von' std :: exception' ist. – sfstewman

+0

@StevenLu: Wenn Ihre Ausnahmeklasse letztlich von 'std :: exception' abgeleitet wird, dann ist das ja ein elegantes Design. Sehen Sie sich die * dritte * Ausnahme mit dem Namen 'your_own_defined_exception' in meinem Beispielcode an. Ich sagte, dass es schließlich von 'std :: exception abgeleitet werden muss. – Nawaz

1

Hauptsächlich weil, wenn Sie mit anderen Leuten arbeiten, Sie sich darauf einigen müssen, was Sie fangen. Wenn ich versuche, eine const std::exception& zu fangen und Sie werfen const char*, dann werde ich nicht Ihre Sachen fangen und schlimme Dinge könnten passieren.

Es spielt keine Rolle, welcher Typ geworfen und gefangen wird, solange jeder daran festhält. Ich denke, std::exception ist über const char* gewählt, weil Sie mehr als nur eine Zeichenfolge in das Ausnahmeobjekt einfügen können. Es ist nur flexibler.

2

Wenn Sie es zu einer Regel in Ihrem Code machen, Ausnahmen auszulösen, die nur von std :: exception abgeleitet werden, ist es einfacher, sie zu fangen. Mit anderen Worten: Sie haben nur eine einzige catch-Klausel auf std :: exception:

catch (std::exception& e) 
{ 
    log_message(e); 
    throw; 
} 

Aber wenn Sie dieser Regel nicht folgen dann Sie am Ende mit catch-Klauseln zu schreiben, wenn Sie nicht haben.

+0

es gibt wenig Vorteil zu fangen und auf jeder Ebene neu zu starten, verwenden Sie nur eine "catch" -Klausel, wenn Sie wirklich etwas zu tun haben (und in C++, mit RAII, sollte dies selten genug sein) oder "schlucken". –

+0

Ich finde es nützlich, um einen Stack-Trace für Ausnahmen zu generieren, die nicht erwartet werden. Es hilft, einen Fehler zu diagnostizieren und zu verfolgen, woher die Ausnahme stammt. – sashang

+0

Ich stimme zu, dass Stapel nützlich sind, aber es gibt zwei Nachteile für Ihren Ansatz. Zuerst wird der Code überladen, es ist nicht mehr offensichtlich, wenn im Ausnahmefall eine * spezifische * Aktion ausgeführt werden soll. Zweitens ist es ein Performance-Hog, weil die Zero Cost-Ausnahme-Implementierung, die von populären Compilern wie gcc oder Clang verwendet wird, eine harte Strafe für Würfe darstellt. Es gibt andere, und ich finde bessere Alternativen. Plattformspezifischer Code zum Erfassen des Stapels am Einwurfpunkt ist eins; Eine andere Möglichkeit besteht darin, mit RAII "Notizen" zu protokollieren, die während des Abwickelns zur Ausnahme hinzugefügt werden. –

1

Ein weiterer Punkt aus er anderen Antworten ist das -

Wenn Sie einen int oder einen String werfen und Sie wollen ein spezifischen Fehler fangen können Sie nicht. Sie müssen alle "int" -Ausnahmen abfangen und dann diejenigen vergleichen, die Sie fangen möchten, und dann alle, mit denen Sie nicht fertig sind, erneut bearbeiten. Wenn Sie von einer Ausnahme erben, können Sie die spezifische Ausnahme abfangen, die Sie behandeln möchten, und haben dennoch den Vorteil, dass Sie nur std :: exception abfangen können, wenn Sie alle behandeln wollen.

Verwandte Themen