with - catch... c++




Schreiben Sie(wirklich) Ausnahme-Code? (9)

Exception Handling (EH) scheint der aktuelle Standard zu sein, und durch die Suche im Internet kann ich keine neuen Ideen oder Methoden finden, die versuchen, sie zu verbessern oder zu ersetzen (naja, einige Variationen existieren, aber nichts Neues).

Obwohl die meisten Leute es zu ignorieren scheinen oder es einfach akzeptieren, hat EH einige große Nachteile: Ausnahmen sind für den Code unsichtbar und es entstehen viele, viele mögliche Austrittspunkte. Joel on Software schrieb einen Artikel darüber . Der Vergleich zu goto passt perfekt, es hat mich wieder über EH nachgedacht.

Ich versuche, EH zu vermeiden und verwende nur Rückgabewerte, Rückrufe oder was auch immer den Zweck erfüllt. Aber wenn Sie zuverlässigen Code schreiben müssen, können Sie EH einfach nicht ignorieren : Es beginnt mit dem new , das eine Ausnahme auslösen kann, anstatt nur 0 (wie in den alten Tagen) zurückzugeben. Dies macht jede Zeile von C ++ - Code anfällig für eine Ausnahme. Und dann werfen mehr Stellen im C ++ - Basiscode Ausnahmen ... std lib tut das und so weiter.

Das fühlt sich an, als würde man auf wackeligen Böden laufen . Jetzt sind wir gezwungen, uns um Ausnahmen zu kümmern!

Aber es ist hart, es ist wirklich schwer. Sie müssen lernen, Ausnahme-Code zu schreiben, und selbst wenn Sie etwas Erfahrung damit haben, wird es immer noch erforderlich sein, jede einzelne Zeile des Codes zu überprüfen, um sicher zu sein! Oder Sie fangen an, überall try / catch-Blöcke zu setzen, was den Code bis zur Unlesbarkeit stopft.

EH ersetzte den alten sauberen deterministischen Ansatz (Rückgabewerte ...), der nur einige, aber verständliche und leicht lösbare Nachteile mit einem Ansatz aufwies, der viele mögliche Ausstiegspunkte in Ihrem Code schafft, und wenn Sie anfangen, Code zu schreiben, der Ausnahmen abfängt Irgendwann muss man das machen), dann erzeugt es sogar eine Vielzahl von Pfaden durch deinen Code (Code in den Catch-Blöcken, denk an ein Server-Programm, wo du andere Logging-Möglichkeiten als std :: cerr brauchst ...). EH hat Vorteile, aber das ist nicht der Punkt.

Meine eigentlichen Fragen:

  • Schreiben Sie wirklich Ausnahmesicherheitscode?
  • Sind Sie sicher, dass Ihr letzter "produktionsfertiger" Code ausnahmslos sicher ist?
  • Kannst du dir sicher sein, dass es so ist?
  • Kennen und / oder verwenden Sie tatsächlich Alternativen, die funktionieren?

Abgesehen von der Verwirrung zwischen SEH- und C ++ - Ausnahmen müssen Sie sich darüber im Klaren sein, dass jederzeit Ausnahmen ausgelöst werden können, und schreiben Sie Ihren Code so. Die Notwendigkeit der Ausnahmesicherheit ist in erster Linie der Motor für die Verwendung von RAII, Smartpointern und anderen modernen C ++ - Techniken.

Wenn Sie den bewährten Mustern folgen, ist das Schreiben von ausnahmesicherem Code nicht besonders schwierig, und tatsächlich ist es einfacher, Code zu schreiben, der Fehler in allen Fällen korrekt behandelt.


Beim Schreiben von ausnahmesicherem Code in C ++ geht es nicht so sehr darum, viele {} catch {} - Blöcke zu verwenden. Es geht darum zu dokumentieren, welche Garantien Ihr Code bietet.

Ich empfehle, Herb Sutters Guru der Woche- Serie zu lesen, insbesondere die Raten 59, 60 und 61.

Zusammenfassend gibt es drei Ebenen der Ausnahmesicherheit, die Sie bereitstellen können:

  • Basic: Wenn Ihr Code eine Ausnahme auslöst, gibt Ihr Code keine Ressourcen frei und Objekte bleiben zerstörbar.
  • Strong: Wenn der Code eine Ausnahme auslöst, bleibt der Status der Anwendung unverändert.
  • Kein Wurf: Dein Code löst niemals Ausnahmen aus.

Ich persönlich habe diese Artikel ziemlich spät entdeckt, daher ist ein Großteil meines C ++ - Codes definitiv nicht ausnahmesicher.


Einige von uns bevorzugen Sprachen wie Java, die uns zwingen, alle von Methoden geworfenen Ausnahmen zu deklarieren, anstatt sie wie in C ++ und C # unsichtbar zu machen.

Wenn sie ordnungsgemäß ausgeführt werden, sind Ausnahmen den Fehlerrückgabecodes überlegen, wenn Sie aus anderen Gründen Fehler nicht manuell in der Aufrufkette weiterleiten müssen.

Allerdings sollte die API-Bibliotheksprogrammierung auf niedriger Ebene wahrscheinlich die Ausnahmebehandlung vermeiden und sich an Fehlerrückgabecodes halten.

Es ist meine Erfahrung, dass es schwierig ist, in C ++ sauberen Ausnahmebehandlungscode zu schreiben. Ich benutze am Ende viel new(nothrow) .


Einige von uns verwenden seit über 20 Jahren eine Ausnahme. PL / I hat sie zum Beispiel. Die Prämisse, dass sie eine neue und gefährliche Technologie sind, erscheint mir fraglich.


Ich arbeite sehr gerne mit Eclipse und Java (neu in Java), weil es Fehler im Editor auslöst, wenn Sie einen EH-Handler verpassen. Das macht es viel schwieriger zu vergessen, eine Ausnahme zu behandeln ...

Außerdem fügt es mit den IDE-Tools den try / catch-Block oder einen anderen catch-Block automatisch hinzu.


Ich versuche mein bestes, ausnahmesicher Code zu schreiben, ja.

Das bedeutet, dass ich darauf achten muss, welche Linien geworfen werden können. Nicht jeder kann dies, und es ist äußerst wichtig, dies zu berücksichtigen. Der Schlüssel ist wirklich, darüber nachzudenken und Ihren Code so zu gestalten, dass er die im Standard definierten Ausnahmegarantien erfüllt.

Kann diese Operation geschrieben werden, um die starke Ausnahme-Garantie zu bieten? Muss ich mich mit dem Grundlegenden begnügen? Welche Zeilen können Ausnahmen auslösen, und wie kann ich sicherstellen, dass sie das Objekt nicht beschädigen, wenn sie dies tun?


Viele (ich würde sogar sagen die meisten) Leute tun.

Bei Ausnahmen ist es sehr wichtig, dass wenn Sie keinen Code schreiben, das Ergebnis absolut sicher und korrekt ist. Zu eifrig in Panik, aber sicher.

Sie müssen in den Handlern aktiv Fehler machen, um etwas unsicher zu machen, und nur fangen (...) {} wird mit dem Ignorieren des Fehlercodes verglichen.


Zuallererst (wie Neil sagte) ist SEH Microsofts Structured Exception Handling. Es ähnelt der Ausnahmeverarbeitung in C ++, ist aber nicht identisch. Tatsächlich müssen Sie C ++ - Ausnahmebehandlung aktivieren, wenn Sie es in Visual Studio möchten - das Standardverhalten garantiert nicht, dass lokale Objekte in allen Fällen zerstört werden! In beiden Fällen ist die Ausnahmebehandlung nicht wirklich schwieriger, sondern nur anders .

Jetzt für Ihre eigentlichen Fragen.

Schreiben Sie wirklich Ausnahmesicherheitscode?

Ja. Ich bemühe mich in allen Fällen um einen Ausnahmecode. Ich missioniere mit RAII-Techniken für den beschränkten Zugriff auf Ressourcen (zB boost::shared_ptr für Speicher, boost::lock_guard für locking). Im Allgemeinen macht die konsistente Verwendung von RAII und RAII Code viel einfacher zu schreiben. Der Trick besteht darin zu lernen, was existiert und wie man es anwendet.

Sind Sie sicher, dass Ihr letzter "produktionsfertiger" Code ausnahmslos sicher ist?

Nein, es ist so sicher wie es ist. Ich kann sagen, dass ich keinen Prozessfehler aufgrund einer Ausnahme in mehreren Jahren 24/7 Aktivität gesehen habe. Ich erwarte keinen perfekten Code, nur gut geschriebenen Code. Die oben genannten Techniken garantieren nicht nur die Ausnahmesicherheit, sondern gewährleisten auch eine Korrektheit, die mit try / catch Blöcken kaum zu erreichen ist. Wenn Sie alles in Ihrem obersten Kontrollbereich erfassen (Thread, Prozess usw.), können Sie sicher sein, dass Sie angesichts von Ausnahmen ( meistens ) weiterlaufen. Die gleichen Techniken werden Ihnen auch helfen, trotz Ausnahmen ohne try / catch Blöcke überall korrekt zu laufen.

Kannst du dir sicher sein, dass es so ist?

Ja. Sie können sicher sein, durch eine gründliche Code-Audit, aber niemand tut das wirklich? Regelmäßige Code-Reviews und sorgfältige Entwickler sind jedoch ein langer Weg dorthin.

Kennen und / oder verwenden Sie tatsächlich Alternativen, die funktionieren?

Ich habe im Laufe der Jahre ein paar Variationen versucht, wie zum Beispiel das Codieren von Zuständen in den oberen Bits (ala HRESULTs ) oder das schreckliche setjmp() ... longjmp() hacken. Beide brechen in der Praxis auf völlig unterschiedliche Weise zusammen.

Am Ende, wenn Sie sich angewöhnen, ein paar Techniken anzuwenden und sorgfältig darüber nachzudenken, wo Sie als Reaktion auf eine Ausnahme tatsächlich etwas tun können, werden Sie mit sehr lesbarem Code enden, der ausnahmslos sicher ist. Sie können dies wie folgt zusammenfassen:

  • Sie möchten nur try / catch wenn Sie etwas zu einer bestimmten Ausnahme machen können
  • Sie möchten fast nie einen new Code sehen oder delete
  • Löschen Sie std::sprintf , snprintf und Arrays im Allgemeinen - verwenden Sie std::ostringstream zum Formatieren und ersetzen Sie Arrays mit std::vector und std::string
  • Suchen Sie im Zweifelsfall nach Funktionen in Boost oder STL, bevor Sie Ihre eigenen erstellen

Ich kann nur empfehlen, dass Sie lernen, wie man Exceptions richtig verwendet, und vergessen Sie Ergebniscodes, wenn Sie in C ++ schreiben wollen. Wenn Sie Ausnahmen vermeiden möchten, sollten Sie in Erwägung ziehen, in einer anderen Sprache zu schreiben, die sie entweder nicht enthält oder die sie sicher macht . Wenn Sie wirklich lernen möchten, C ++ vollständig zu nutzen, lesen Sie ein paar Bücher von Herb Sutter , Nicolai Josuttis und Scott Meyers .


  • Schreiben Sie wirklich Ausnahmesicherheitscode? [Das gibt es nicht. Ausnahmen sind ein Papierschild für Fehler, es sei denn, Sie haben eine verwaltete Umgebung. Dies gilt für die ersten drei Fragen.]

  • Kennen und / oder verwenden Sie tatsächlich Alternativen, die funktionieren? [Alternative zu was? Das Problem hierbei ist, dass Leute tatsächliche Fehler nicht vom normalen Programmbetrieb trennen. Wenn es sich um einen normalen Programmbetrieb handelt (dh eine Datei wurde nicht gefunden), handelt es sich nicht wirklich um eine Fehlerbehandlung. Wenn es sich um einen tatsächlichen Fehler handelt, gibt es keine Möglichkeit, es zu behandeln, oder es handelt sich nicht um einen tatsächlichen Fehler. Ihr Ziel ist es, herauszufinden, was schief gelaufen ist und entweder die Tabelle zu stoppen und einen Fehler zu protokollieren, den Treiber für Ihren Toaster neu zu starten oder einfach zu beten, dass der Jetfighter weiterfliegen kann, selbst wenn Software fehlerhaft ist und hoffen auf das Beste.





exception-handling