Historie der Frage:
Der Mechanismus der Ausnahmebehandlung wurde in C++ eingeführt, um eine zuverlässigere und strukturierte Fehlerbehandlung zu gewährleisten, im Gegensatz zu Rückgabewerten. Im Laufe der Jahre hat sich die Syntax erweitert, und es wurden Spezifizierer wie noexcept eingeführt, um die Unterbrechung des Werfens von Ausnahmen aus Funktionen zu steuern.
Problem:
Falsche Handhabung von Ausnahmen führt oft zu Speicherlecks, unbestimmtem Verhalten oder Abstürzen von Anwendungen. Wenn das Werfen von Ausnahmen aus Konstruktoren, Destruktoren oder beim Arbeiten mit Ressourcen nicht berücksichtigt wird, ergibt sich ein ernstes Problem mit dem Zustand des Programms.
Lösung:
Die Grundsyntax ist die Verwendung von try-catch. Ausnahmen können jeden Typ haben, es wird jedoch empfohlen, benutzerdefinierte Ausnahmen von std::exception abzuleiten. Das Schlüsselwort noexcept (C++11+) gibt an, dass eine Funktion keine Ausnahmen werfen sollte; das Werfen einer Ausnahme aus einer noexcept-Funktion führt zu std::terminate().
Beispielcode:
#include <iostream> #include <stdexcept> void func() noexcept(false) { throw std::runtime_error("Error!"); } int main() { try { func(); } catch(const std::exception& ex) { std::cout << ex.what(); } }
Wichtige Merkmale:
Darf man Ausnahmen im Destruktor werfen?
Nein, das Werfen einer Ausnahme aus einem Destruktor während des Stack-Unwind führt zu std::terminate(). Ausnahmen im Destruktor sollten innerhalb des Destruktors selbst abgefangen werden.
Was passiert, wenn man eine Ausnahme aus einer noexcept-Funktion wirft?
Es wird std::terminate ausgelöst, das Programm wird abnormal beendet. noexcept ist ein strenger Vertrag.
Kann man Ausnahmen nach Wert auffangen? Wie gefährlich ist das?
Man kann nach Wert abrufen, aber das Objekt wird kopiert (object slicing). Es wird empfohlen, const & zu verwenden.
Beispielcode:
try { throw std::out_of_range("err"); } catch (const std::exception& e) { /* ... */ }
Der Code warf Ausnahmen in Destruktoren von Ressourcen; bei einem abnormalen Abschluss wurde der Stack nicht richtig zurückverfolgt, und Ressourcen blieben als Leck bestehen.
Vorteile:
Nachteile:
Kritische Methoden wurden mit noexcept gekennzeichnet, Destruktoren fingen alle Ausnahmen intern ab. Es wurden catch-Referenzen verwendet, alle Fehler wurden protokolliert.
Vorteile:
Nachteile: