Unterschied: std :: runtime_error vs std :: exception ()

127

Was ist der Unterschied zwischen std::runtime_errorund std::exception? Was ist die richtige Verwendung für jeden? Warum unterscheiden sie sich überhaupt?

Sivabudh
quelle

Antworten:

152

std::exceptionist die Klasse, deren einziger Zweck darin besteht, als Basisklasse in der Ausnahmehierarchie zu dienen. Es hat keine anderen Verwendungen. Mit anderen Worten, konzeptionell ist es eine abstrakte Klasse (obwohl sie in der C ++ - Bedeutung des Begriffs nicht als abstrakte Klasse definiert ist).

std::runtime_errorist eine speziellere Klasse, die von std::exceptionverschiedenen Klassen abstammt und bei verschiedenen Laufzeitfehlern ausgelöst werden soll. Es hat einen doppelten Zweck. Es kann selbst geworfen werden, oder es kann auf verschiedene noch mehr spezialisierte Arten von Laufzeitfehlern Ausnahmen, wie zB als Basisklasse dienen std::range_error, std::overflow_errorusw. Sie können Ihre eigenen Ausnahmeklassen absteigend von definieren std::runtime_error, sowie Sie können Ihre eigene Ausnahme definieren Klassen absteigend von std::exception.

Genau wie die std::runtime_errorStandardbibliothek enthält std::logic_error, auch absteigend von std::exception.

Der Sinn dieser Hierarchie besteht darin, dem Benutzer die Möglichkeit zu geben, die volle Leistungsfähigkeit des C ++ - Ausnahmebehandlungsmechanismus zu nutzen. Da die 'catch'-Klausel polymorphe Ausnahmen abfangen kann, kann der Benutzer' catch'-Klauseln schreiben, die Ausnahmetypen aus einem bestimmten Teilbaum der Ausnahmehierarchie abfangen können. Fängt beispielsweise catch (std::runtime_error& e)alle Ausnahmen vom std::runtime_errorTeilbaum ab und lässt alle anderen durch (und fliegt weiter den Aufrufstapel hinauf).

PS Das Entwerfen einer nützlichen Ausnahmeklassenhierarchie (mit der Sie nur die Ausnahmetypen abfangen können, an denen Sie an jedem Punkt Ihres Codes interessiert sind) ist keine triviale Aufgabe. Was Sie in der Standard-C ++ - Bibliothek sehen, ist ein möglicher Ansatz, den Ihnen die Autoren der Sprache anbieten. Wie Sie sehen, haben sie beschlossen, alle Ausnahmetypen in "Laufzeitfehler" und "Logikfehler" aufzuteilen und von dort aus mit Ihren eigenen Ausnahmetypen fortzufahren. Es gibt natürlich alternative Möglichkeiten, diese Hierarchie zu strukturieren, die für Ihr Design möglicherweise besser geeignet sind.

Update: Portabilität Linux vs Windows

Wie Loki Astari und unixman83 in ihrer Antwort und ihren Kommentaren unten angegeben haben, akzeptiert der Konstruktor der exceptionKlasse keine Argumente gemäß dem C ++ - Standard. Microsoft C ++ verfügt über einen Konstruktor, der Argumente in der exceptionKlasse akzeptiert, dies ist jedoch kein Standard. Die runtime_errorKlasse verfügt über einen Konstruktor, der char*auf beiden Plattformen, Windows und Linux , Argumente ( ) verwendet. Um tragbar zu sein, besser nutzen runtime_error.

(Und denken Sie daran: Nur weil eine Spezifikation Ihres Projekts besagt, dass Ihr Code nicht unter Linux ausgeführt werden muss, bedeutet dies nicht, dass er niemals unter Linux ausgeführt werden muss.)

Ameise
quelle
1
Danke. gute Antwort. obwohl ich mich frage, ob es jemals eine Notwendigkeit gibt, eine andere Art von Ausnahme zu haben ... nur ein Gedanke.
Sivabudh
1
Wenn es eine Möglichkeit gibt, von der die Ausnahme erneut abgedeckt werden kann, kann ein anderer Ausnahmetyp hilfreich sein, da wir den Ausnahmebehandlungsmechanismus verwenden können, um die Ausnahme an den Handler weiterzuleiten, der versucht, das Problem zu beheben. Wenn keine Chance auf Wiederherstellung besteht, ist eine der Standardausnahmen in Ordnung.
Martin York
1
Nebenbei bemerkt: Es gibt nirgendwo eine Regel, die Sie dazu zwingt, sich abzuleiten std::exception. Sicher, alle stdDinge werfen abgeleitete Klassen davon, aber es gibt absolut keinen Grund, nur std::exceptionabgeleitete Objekte zu werfen .
Rubenvb
1
@rubenvb Das wusste ich nicht, aber ich denke, es wird den Code für zukünftige Wartungsarbeiten klarstellen, wenn nur Objekte von Klassen ausgelöst werden, die von einer Ausnahme abgeleitet sind. Beispiel: Ich möchte herausfinden, welche benutzerdefinierten Ausnahmen in meiner Codebasis implementiert sind, und nach Klassen suchen, die von Ausnahmen abgeleitet sind.
this.myself
21

std::exceptionsollte als abstrakte Basis der Standardausnahmehierarchie betrachtet werden (beachten Sie die berücksichtigte). Dies liegt daran, dass es keinen Mechanismus gibt, um eine bestimmte Nachricht weiterzuleiten (dazu müssen Sie ableiten und spezialisieren what()). Nichts hindert Sie daran, std :: exception zu verwenden, und für einfache Anwendungen ist dies möglicherweise alles, was Sie benötigen.

std::runtime_errorAuf der anderen Seite gibt es gültige Konstruktoren, die eine Zeichenfolge als Nachricht akzeptieren. Wenn what()aufgerufen wird, wird ein const char-Zeiger zurückgegeben, der auf eine C-Zeichenfolge zeigt, die dieselbe Zeichenfolge hat, die an den Konstruktor übergeben wurde.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 
Martin York
quelle
1
Danke für die Antwort Martin. Ich benutze jedoch std :: exception () auf die gleiche Weise wie oben beschrieben. Der Konstruktor std :: exception () kann auch einen std :: string () oder const char * verwenden.
Sivabudh
14
Nicht nach dem Standard. std :: exception hat einen Konstruktor, der keine Argumente akzeptiert. Die Verwendung einer Version, die einen std :: string oder einen C-String akzeptiert, ist nicht portierbar.
Martin York
10
Wegen Microsoft habe ich mich an das Werfen gewöhnt std::exception(std::string). Jetzt ist mir klar, dass ich werfen muss, std::runtime_errorwenn mein Code unter Linux (GCC) funktionieren soll.
Unixman83