Namensräume
Varianten
Aktionen

Ausnahmen

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
Ausnahmen
 

Die Ausnahmebehandlung bietet eine Möglichkeit, die Kontrolle und Informationen von einem Punkt in der Ausführung eines Programms zu einem Handler zu übertragen, der mit einem zuvor durchlaufenen Punkt der Ausführung assoziiert ist (mit anderen Worten, die Ausnahmebehandlung überträgt die Kontrolle den Aufrufstapel hinauf).

Die Auswertung eines throw Ausdrucks wirft eine Ausnahme. Ausnahmen können auch in anderen Kontexten geworfen werden.

Damit eine Ausnahme abgefangen werden kann, muss der throw Ausdruck innerhalb eines try Blocks stehen und der try Block muss einen Handler enthalten, der mit dem Typ des Ausnahmeobjekts übereinstimmt.

Bei der Deklaration einer Funktion können die folgenden Spezifikationen angegeben werden, um die Typen der Ausnahmen zu beschränken, die eine Funktion werfen darf.

(bis C++17)
(seit C++11)

Fehler, die während der Ausnahmebehandlung auftreten, werden von std::terminate und std::unexpected(bis C++17) behandelt.

Inhalt

[bearbeiten] Verwendung

Während der throw Ausdruck verwendet werden kann, um die Kontrolle aus beliebigen Gründen zu einem beliebigen Codeblock auf dem Ausführungsstapel zu übertragen (ähnlich wie bei std::longjmp), ist seine beabsichtigte Verwendung die Fehlerbehandlung.

[bearbeiten] Fehlerbehandlung

Das Werfen einer Ausnahme wird verwendet, um Fehler aus Funktionen zu signalisieren, wobei "Fehler" typischerweise auf nur die folgenden beschränkt sind[1][2][3]

  1. Fehler bei der Einhaltung der Nachbedingungen, wie z. B. das Nicht-Erzeugen eines gültigen Rückgabewertobjekts.
  2. Fehler bei der Einhaltung der Vorbedingungen einer anderen Funktion, die aufgerufen werden muss.
  3. (für nicht-private Member-Funktionen) Fehler bei der (Wieder-)Herstellung einer Klasseninvarianten.

Insbesondere bedeutet dies, dass Fehler von Konstruktoren (siehe auch RAII) und den meisten Operatoren durch das Werfen von Ausnahmen gemeldet werden sollten.

Darüber hinaus verwenden sogenannte *Wide-Contract*-Funktionen Ausnahmen, um inakzeptable Eingaben anzuzeigen, z. B. hat std::basic_string::at keine Vorbedingungen, wirft aber eine Ausnahme, um einen ungültigen Index anzuzeigen.

[bearbeiten] Ausnahmensicherheit

Nachdem der Fehlerzustand von einer Funktion gemeldet wurde, können zusätzliche Garantien bezüglich des Zustands des Programms gegeben werden. Die folgenden vier Stufen der Ausnahmegarantie werden im Allgemeinen anerkannt[4][5][6], die echte Obermengen voneinander sind.

  1. Nothrow- (oder Nofail-) Ausnahmegarantie — die Funktion wirft niemals Ausnahmen. Nothrow (Fehler werden anderweitig gemeldet oder verborgen) wird von Destruktoren und anderen Funktionen erwartet, die während des Stapel-Unwinding aufgerufen werden können. Die Destruktoren sind standardmäßig noexcept.(seit C++11) Nofail (die Funktion ist immer erfolgreich) wird von Swaps, Move-Konstruktoren und anderen Funktionen erwartet, die von denen verwendet werden, die eine starke Ausnahmegarantie bieten.
  2. Starke Ausnahmegarantie — Wenn die Funktion eine Ausnahme wirft, wird der Zustand des Programms auf den Zustand vor dem Funktionsaufruf zurückgerollt (z. B. std::vector::push_back).
  3. Grundlegende Ausnahmegarantie — Wenn die Funktion eine Ausnahme wirft, befindet sich das Programm in einem gültigen Zustand. Keine Ressourcen werden geleakt, und alle Objektinvarianten sind intakt.
  4. Keine Ausnahmegarantie — Wenn die Funktion eine Ausnahme wirft, befindet sich das Programm möglicherweise nicht in einem gültigen Zustand: Ressourcenlecks, Speicherbeschädigung oder andere invarianzenzerstörende Fehler können aufgetreten sein.

Generische Komponenten können zusätzlich eine *Ausnahme-neutrale Garantie* bieten: Wenn eine Ausnahme von einem Template-Parameter geworfen wird (z. B. vom `Compare`-Funktionsobjekt von std::sort oder vom Konstruktor von `T` in std::make_shared), wird sie unverändert an den Aufrufer weitergegeben.

[bearbeiten] Ausnahmeobjekte

Während Objekte jedes vollständigen Typs und cv-Zeiger auf void als Ausnahmeobjekte geworfen werden können, werfen alle Standardbibliotheksfunktionen namenlose Objekte per Wert, und die Typen dieser Objekte leiten sich (direkt oder indirekt) von std::exception ab. Benutzerdefinierte Ausnahmen folgen normalerweise diesem Muster.[7][8][9]

Um unnötiges Kopieren des Ausnahmeobjekts und Objekt-Slicing zu vermeiden, ist die beste Vorgehensweise für Handler, per Referenz abzufangen.[10][11][12][13]

[bearbeiten] Anmerkungen

Feature-Testmakro Wert Std Feature
__cpp_constexpr_exceptions 202411L (C++26) constexpr Ausnahmen

[bearbeiten] Externe Links

  1. H. Sutter (2004) "When and How to Use Exceptions" in Dr. Dobb's
  2. H. Sutter, A. Alexandrescu (2004), "C++ Coding Standards", Item 70
  3. C++ Core Guidelines I.10: Use exceptions to signal a failure to perform a required task
  4. B. Stroustrup (2000), "The C++ Programming Language" Appendix E
  5. H. Sutter (2000) "Exceptional C++"
  6. D. Abrahams (2001) "Exception Safety in Generic Components"
  7. D. Abrahams (2001) "Error and Exception Handling"
  8. isocpp.org Super-FAQ "What should I throw?"
  9. C++ Core Guidelines E.14: Use purpose-designed user-defined types as exceptions (not built-in types)
  10. C++ Core Guidelines E.15: Throw by value, catch exceptions from a hierarchy by reference
  11. S. Meyers (1996) "More Effective C++" Item 13
  12. isocpp.org Super-FAQ "What should I catch?"
  13. H. Sutter, A. Alexandrescu (2004) "C++ Coding Standards" Item 73