Während ich meine erste "ernsthafte" C ++ - Bibliothek entwerfe, frage ich mich:
Ist es gut, Ausnahmen von std::exception
und Nachkommen abzuleiten ?!
Auch nach dem Lesen
- Entwerfen von Ausnahmeklassen
- Was ist eine "gute Anzahl" von Ausnahmen, die für meine Bibliothek implementiert werden müssen?
Ich bin mir immer noch nicht sicher. Weil ich als Bibliotheksbenutzer neben der üblichen (aber möglicherweise nicht guten) Praxis davon ausgehen würde, dass eine Bibliotheksfunktion std::exception
s nur dann auslöst, wenn Standard-Bibliotheksfunktionen in der Bibliotheksimplementierung fehlschlagen, und nichts dagegen tun kann. Aber immer noch, wenn ich Anwendungscode schreibe, ist das für mich sehr praktisch, und meiner Meinung nach sieht es auch gut aus, einfach einen zu werfen std::runtime_error
. Auch meine User können sich ebenfalls auf die definierte Mindestschnittstelle verlassen, wie zum Beispiel what()
oder Codes.
Und zum Beispiel, mein Benutzer liefert fehlerhafte Argumente, was wäre bequemer, als ein zu werfen std::invalid_argument
, nicht wahr? So kombiniert mit der noch häufigen Verwendung von std :: exception sehe ich in anderen Code: Warum nicht noch weiter gehen und von Ihrer benutzerdefinierten Ausnahmeklasse (zB lib_foo_exception) und auch von ableiten std::exception
.
Gedanken?
quelle
std::exception
nicht Sie bedeutet werfen einstd::exception
. Auchstd::runtime_error
erbt vonstd::exception
in erster Linie, und diewhat()
Methode kommtstd::exception
nicht vonstd::runtime_error
. Und Sie sollten auf jeden Fall Ihre eigenen Ausnahmeklassen erstellen, anstatt generische Ausnahmen wiestd::runtime_error
.lib_foo_exception
Klasse davon ableitetstd::exception
,lib_foo_exception
nur fangen würdestd::exception
, zusätzlich dazu, wenn er nur die Bibliothek fängt. Also könnte ich auch fragen, ob meine Bibliotheksausnahmestammklasse von std :: exception erbt .lib_foo_exception
?" Mit dem Erben vonstd::exception
können Sie es durchcatch(std::exception)
ODER durch tuncatch(lib_foo_exception)
. Ohne Ableitung ausstd::exception
, würden Sie es fangen , wenn und nur wenn durchcatch(lib_foo_exception)
.catch(...)
. Es ist vorhanden, weil die Sprache den von Ihnen in Betracht gezogenen Fall (und das "schlechte Benehmen" von Bibliotheken) berücksichtigt, aber dies ist keine moderne Best Practice.catch
Sites und ebenso gröbere Transaktionen anzuregen, die eine Benutzerendoperation modellieren. Wenn Sie es mit Sprachen vergleichen, die die Idee des generalisierten Fangens von nicht fördernstd::exception&
, haben sie beispielsweise oft viel mehr Code mit Zwischenblöckentry/catch
, die mit sehr spezifischen Fehlern behaftet sind, was die Allgemeingültigkeit der Ausnahmebehandlung etwas verringert, wenn sie beginnt zu platzieren Eine viel stärkere Betonung liegt auf der manuellen Fehlerbehandlung und auch auf allen unterschiedlichen Fehlern, die möglicherweise auftreten können.Antworten:
Alle Ausnahmen sollten von erben
std::exception
.Nehmen wir zum Beispiel an, ich muss anrufen
ComplexOperationThatCouldFailABunchOfWays()
und möchte alle Ausnahmen behandeln, die es auslösen könnte. Wenn alles von erbtstd::exception
, ist das einfach. Ich brauche nur einen einzigencatch
Block und habe eine Standardschnittstelle (what()
), um Details zu erhalten.Wenn Ausnahmen NICHT von erben
std::exception
, wird dies viel hässlicher:Über das Werfen
runtime_error
oder dasinvalid_argument
Erstellen eigenerstd::exception
Unterklassen zum Werfen: Als Faustregel gilt, wenn ich einen bestimmten Fehlertyp anders als andere Fehler behandeln muss (dh wenn ich einen separatencatch
Block benötige), eine neue Unterklasse einzuführen .runtime_error
geworfener Wert etwas anderes als einen generischen Laufzeitfehler bedeutet), laufe ich Gefahr, mit anderen Verwendungen der vorhandenen Unterklasse in Konflikt zu geraten.invalid_argument
), dann wieder verwende ich die vorhandene Klasse. In diesem Fall sehe ich keinen großen Vorteil darin, eine neue Klasse hinzuzufügen. (Die C ++ Core Guidelines stimmen hier nicht mit mir überein - sie empfehlen, immer Ihre eigenen Klassen zu verwenden.)Die C ++ Core Guidelines enthalten weitere Diskussionen und Beispiele.
quelle
catch (...)
(mit der wörtlichen Ellipse) ist für?catch (...)
ist nur nützlich, wenn Sie nichts mit dem tun müssen, was geworfen wird. Wenn Sie etwas tun möchten, z. B. die spezifische Fehlermeldung wie in meinem Beispiel anzeigen oder protokollieren, müssen Sie wissen, um was es sich handelt.Das ist eine falsche Annahme.
Die Standardausnahmetypen sind für die "allgemeine" Verwendung vorgesehen. Sie sind nicht nur für die Verwendung durch die Standardbibliothek vorgesehen.
Ja, alles letztendlich erben lassen
std::exception
. Oft geht es darum, vonstd::runtime_error
oder zu erbenstd::logic_error
. Was auch immer für die Ausnahmeklasse geeignet ist, die Sie implementieren.Dies ist natürlich subjektiv - einige populäre Bibliotheken ignorieren die Standardausnahmetypen vollständig, vermutlich, um die Bibliotheken von der Standardbibliothek zu entkoppeln. Persönlich finde ich das extrem egoistisch! Es macht es sehr viel schwieriger, Ausnahmen zu fangen.
Wenn ich persönlich spreche, werfe ich oft einfach ein
std::runtime_error
und bin fertig damit. Aber das ist eine Diskussion darüber, wie detailliert Ihre Ausnahmeklassen erstellt werden sollen, was nicht Ihre Frage ist.quelle