Du musst nicht jeden Block mit try-catches abdecken, denn ein try-catch kann immer noch unbehandelte Ausnahmen abfangen, die in Funktionen weiter unten im Aufrufstapel geworfen werden. Anstatt also jedet Funktion ein try-catch haben zu lassen, kannst du eine auf der Top-Level-Logik deiner Anwendung haben. Zum Beispiel könnte es eine SaveDocument()
Top-Level-Routine geben, die viele Methoden aufruft, die wiederum andere Methoden aufrufen usw. Diese Untermethoden benötigen keine eigenen try-catches, denn wenn sie eine Ausnahme werfen, wird diese immer noch vom SaveDocument()
-Catch abgefangen.
Dies hat drei Vorteile: Praktisch ist es, weil du einen einzigen Ort hast, um einen Fehler zu melden: die SaveDocument()
Catch-Blöcke. Es ist nicht nötig, dies in allen Untermethoden zu wiederholen, und es ist sowieso das, was du willst: einen einzigen Ort, an dem du dem Benutzer eine nützliche Diagnose über etwas geben kannst, das schief gelaufen ist.
Zweitens wird der Speichervorgang abgebrochen, wenn eine Ausnahme geworfen wird. Bei jedem try-catch in den Unterfunktionen wird, wenn eine Ausnahme geworfen wird, in den entsprechenden Catch-Block der Methode gesprungen, die Ausführung verlässt die Funktion, und es geht durch SaveDocument()
weiter. Wenn bereits etwas schief gelaufen ist, möchtest du wahrscheinlich genau an dieser Stelle stoppen.
Drittens gehen alle deine Unterfunktionen davon aus, dass jeder Aufruf erfolgreich ist. Falls ein Aufruf fehlschlägt, springt die Ausführung zum Catch-Block und der nachfolgende Code wird nie ausgeführt. Das kann deinen Code viel sauberer machen. Zum Beispiel, hier ist es mit Fehlercodes:
int ret = SaveFirstSection();
if (ret == FAILED)
{
/* irgendeine Diagnose */
return;
}
ret = SaveSecondSection();
if (ret == FAILED)
{
/* irgendeine Diagnose */
return;
}
ret = SaveThirdSection();
if (ret == FAILED)
{
/* irgendeine Diagnose */
return;
}
So könnte es mit Ausnahmen geschrieben werden:
// diese werfen bei einem Fehler, werden im SaveDocument-Catch abgefangen
SaveFirstSection();
SaveSecondSection();
SaveThirdSection();
Jetzt ist viel klarer, was passiert.
Beachte, dass das Schreiben von code, der Ausnahmesicher ist, auf andere Weise knifflig sein kann: Du möchtest keinen Speicherlecks haben, wenn eine Ausnahme geworfen wird. Achte darauf, dass du über RAII, STL Container, Smart Pointer und andere Objekte Bescheid weißt, die ihre Ressourcen in Destruktoren freigeben, da Objekte immer vor Ausnahmen zerstört werden.