482 Stimmen

Warum sollte ich nicht jeden Block in "try"-"catch" einpacken?

Ich war schon immer der Überzeugung, dass es fahrlässig ist, einen Aufruf, der eine Ausnahme werfen kann, nicht mit einem sinnvollen try-Block zu schützen.

Ich habe gerade "Sie sollten IMMER Aufrufe, die eine Ausnahme werfen können, in try-catch-Blöcke einpacken." zu dieser Frage gepostet und mir wurde gesagt, dass es sich um 'bemerkenswert schlechten Rat' handelt - Ich würde gerne verstehen, warum.

5voto

Bananeweizen Punkte 21303

Ich stimme der Grundrichtung Ihrer Frage zu, so viele Ausnahmen wie möglich auf niedrigster Ebene zu behandeln.

Einige der bisherigen Antworten lauten: "Sie müssen die Ausnahme nicht behandeln. Jemand anderes wird es weiter oben im Stapel tun." Meiner Erfahrung nach ist das eine schlechte Ausrede, um nicht über die Ausnahmebehandlung nachzudenken im gerade entwickelten Code-Stück, und die Ausnahmebehandlung zum Problem von jemand anderem oder später zu machen.

Dieses Problem wächst dramatisch im verteilten Entwicklungsbereich, wo Sie möglicherweise eine Methode aufrufen müssen, die von einem Kollegen implementiert wurde. Und dann müssen Sie eine verschachtelte Kette von Methodenaufrufen inspizieren, um herauszufinden, warum er/sie eine Ausnahme an Sie wirft, die viel einfacher in der tiefsten verschachtelten Methode hätte behandelt werden können.

3voto

bluedog Punkte 935

Wenn Sie das Ergebnis jeder Funktion testen möchten, verwenden Sie Rückgabecodes.

Der Zweck von Ausnahmen besteht darin, dass Sie die Ergebnisse WENIGER oft testen können. Die Idee ist, außergewöhnliche (ungewöhnliche, seltenere) Bedingungen aus Ihrem gewöhnlicheren Code herauszutrennen. Dadurch bleibt der gewöhnliche Code sauberer und einfacher - und kann dennoch mit diesen außergewöhnlichen Bedingungen umgehen.

In gut gestaltetem Code könnten tiefere Funktionen Ausnahmen auslösen und höhere Funktionen einfangen. Aber der Schlüssel ist, dass viele Funktionen "dazwischen" vollständig von der Last befreit sind, außergewöhnliche Bedingungen zu behandeln. Sie müssen nur "ausnahmesicher" sein, was nicht bedeutet, dass sie einfangen müssen.

3voto

GPMueller Punkte 2377

Ich würde gerne zu dieser Diskussion hinzufügen, dass es seit C++11 durchaus Sinn macht, solange jeder catch-Block die Ausnahme bis zu dem Punkt, an dem sie gehandhabt werden kann/sollte, rethrowt Ein Backtrace kann auf diese Weise generiert werden. Ich glaube daher, dass die vorherigen Meinungen teilweise veraltet sind.

Verwenden Sie std::nested_exception und std::throw_with_nested

Es wird auf StackOverflow hier und hier beschrieben, wie dies erreicht werden kann.

Da Sie dies mit jeder abgeleiteten Ausnahmeklasse tun können, können Sie viele Informationen zu einem solchen Backtrace hinzufügen! Sie können auch einen Blick auf mein MWE auf GitHub werfen, wo ein Backtrace ähnlich wie folgt aussehen würde:

Bibliotheks-API: Ausnahme in Funktion 'api_function' gefangen
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function fehlgeschlagen
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : konnte Datei "nonexistent.txt" nicht öffnen

1voto

zhaorufei Punkte 1877

Neben dem obigen Ratschlag verwende ich persönlich einige try+catch+throw aus folgendem Grund:

  1. Am Rand verschiedener Codierer verwende ich try + catch + throw in meinem eigenen Code, bevor die Ausnahme an den Aufrufer weitergegeben wird, der von anderen geschrieben wurde. Dies gibt mir die Möglichkeit zu wissen, dass ein Fehlerzustand in meinem Code aufgetreten ist, und dieser Ort ist viel näher am Code, der die Ausnahme initial ausgelöst hat, je näher, desto einfacher ist es, den Grund zu finden.
  2. Am Rand von Modulen, obwohl verschiedene Module vom selben Verfasser verfasst sein können.
  3. Zum Lern- und Debug-Zweck verwende ich in diesem Fall catch(...) in C++ und catch(Exception ex) in C#. In C++ wirft die Standardbibliothek nicht allzu viele Ausnahmen, daher ist dieser Fall in C++ selten. Aber in C# ist dies ein häufiger Fall, C# hat eine riesige Bibliothek und eine ausgereifte Ausnahmehierarchie, der C#-Bibliothekscode wirft Tonnen von Ausnahmen. Theoretisch sollte ich (und auch du) über jede Ausnahme in der Funktion, die du aufgerufen hast, Bescheid wissen und den Grund/Fall kennen, warum diese Ausnahmen ausgelöst werden, und wissen, wie man sie angemessen behandelt (weitergeben oder an dieser Stelle auffangen und behandeln). Leider ist es in der Realität sehr schwer, alles über die potenziellen Ausnahmen zu wissen, bevor ich eine Zeile Code schreibe. Also fange ich alles ab und lasse meinen Code laut sprechen, indem ich ihn protokolliere (in der Produktumgebung) / Assert-Dialog (in der Entwicklungsumgebung), wenn eine Ausnahme tatsächlich auftritt. Auf diese Weise füge ich schrittweise Ausnahmebehandlungscode hinzu. Ich weiß, dass das im Widerspruch zu gutem Rat steht, aber in der Realität funktioniert es für mich und ich kenne keinen besseren Weg für dieses Problem.

1voto

user875234 Punkte 2151

Ich fühle mich verpflichtet, eine weitere Antwort hinzuzufügen, obwohl die Antwort von Mike Wheat die Hauptpunkte ziemlich gut zusammenfasst. Ich denke so darüber nach. Wenn Sie Methoden haben, die mehrere Dinge tun, multiplizieren Sie die Komplexität, nicht addieren sie.

Anders ausgedrückt, eine Methode, die in einem Try-Catch-Block eingewickelt ist, hat zwei mögliche Ergebnisse. Sie haben das nicht-Exception-Ergebnis und das Exception-Ergebnis. Wenn Sie es mit vielen Methoden zu tun haben, explodiert dies exponentiell über das Verständnis hinaus.

Exponentiell, weil wenn jede Methode sich in zwei verschiedene Richtungen verzweigt, werden jedes Mal, wenn Sie eine weitere Methode aufrufen, die vorherige Anzahl der potenziellen Ergebnisse quadriert. Bis Sie fünf Methoden aufgerufen haben, sind Sie auf mindestens 256 mögliche Ergebnisse angewachsen. Vergleichen Sie dies mit dem nicht Verwenden eines Try/Catch in jeder einzelnen Methode und Sie haben nur einen Pfad zu verfolgen.

So in etwa sehe ich das. Man könnte versucht sein zu argumentieren, dass jede Art von Verzweigung dasselbe tut, aber Try/Catches sind ein besonderer Fall, weil der Zustand der Anwendung im Grunde genommen undefiniert wird.

Kurz gesagt, machen Try/Catches den Code viel schwerer verständlich.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X