ProgrammierungC++ Systemprogrammierer

Erzählen Sie mir von den Mechanismen der Ausnahmebehandlung (exceptions) in C++. Wie behandelt man Fehler korrekt und wozu dient noexcept?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

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:

  • Ausnahmen sorgen für automatisches Unwinding (Stack-Rückverfolgung)
  • noexcept ermöglicht dem Compiler zu optimieren, wenn die Funktion garantiert keine Ausnahmen wirft
  • Nur std::exception und ihre Abkömmlinge garantieren das Vorhandensein der Methode what()

Fangfragen.

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) { /* ... */ }

Typische Fehler und Anti-Patterns

  • Verwendung von throw in Destruktoren
  • Abschlucken von Ausnahmen catch(...) ohne Protokollierung
  • Nichtangabe von noexcept, wo möglich

Beispiel aus dem Leben

Negativer Fall

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:

  • Schnelle Fehlererkennung möglich

Nachteile:

  • Programme wurden häufig mit einem Fehler terminate beendet

Positiver Fall

Kritische Methoden wurden mit noexcept gekennzeichnet, Destruktoren fingen alle Ausnahmen intern ab. Es wurden catch-Referenzen verwendet, alle Fehler wurden protokolliert.

Vorteile:

  • Zuverlässigkeit, keine Lecks
  • Extrem vorhersehbares Verhalten

Nachteile:

  • Erhöhte Strenge für den Entwickler beim Schreiben von korrektem, „sauberem“ Code