6 Ausnahmebehandlung

6.1 Exceptions

Ausnahmebehandlung ist ein Mechanismus, der es einem Programm ermöglicht, auf unerwartete oder außergewöhnliche Laufzeitbedingungen zu reagieren und angemessen darauf zu antworten, anstatt abzustürzen oder undefiniertes Verhalten zu erzeugen.

6.1.1 Grundlagen der Ausnahmebehandlung

6.1.2 Verwendung

Eine Ausnahme auslösen:

throw std::runtime_error("Ein Fehler ist aufgetreten!");

Eine Ausnahme fangen und behandeln:

try {
    // Code, der möglicherweise eine Ausnahme auslöst
    throw std::runtime_error("Ein Fehler ist aufgetreten!");
} catch (const std::runtime_error &e) {
    std::cerr << "Runtime error: " << e.what() << std::endl;
} catch (...) {
    std::cerr << "Ein unbekannter Fehler ist aufgetreten!" << std::endl;
}

6.1.3 Standardausnahmen

C++ stellt eine Reihe von Standardausnahmeklassen im Header <stdexcept> zur Verfügung, darunter:

Viele weitere spezifische Ausnahmeklassen sind abgeleitet von diesen Basisklassen.

6.1.4 Eigene Ausnahme-Klassen erstellen

Man kann auch eigene Ausnahmeklassen erstellen, indem man von std::exception oder einer seiner abgeleiteten Klassen erbt:

class MyException : public std::exception {
    const char* what() const noexcept override {
        return "Mein eigener Fehler!";
    }
};

6.1.5 Wichtige Punkte zur Ausnahmebehandlung

  1. Nicht für reguläre Steuerungsflüsse: Ausnahmen sollten nur für tatsächliche “Ausnahmen” verwendet werden, d.h. unerwartete oder ungewöhnliche Bedingungen, und nicht für den regulären Steuerungsfluss eines Programms.
  2. Leistungsaspekte: Das Werfen und Fangen von Ausnahmen kann teuer sein. Vermeiden Sie daher das übermäßige Werfen von Ausnahmen in leistungsintensiven Bereichen des Codes.
  3. Stack Unwinding: Wenn eine Ausnahme geworfen wird, wird der Stack “unwound”, was bedeutet, dass lokale Objekte in umgekehrter Reihenfolge ihrer Erstellung destruiert werden, bis ein passender Catch-Block gefunden wird.
  4. Ressourcenfreigabe: Achten Sie darauf, alle Ressourcen ordnungsgemäß freizugeben, wenn eine Ausnahme geworfen wird, insbesondere bei der manuellen Speicherverwaltung. (Smart Pointer können hier hilfreich sein!)

6.1.6 TLDR;

Die Ausnahmebehandlung in C++ bietet einen strukturierten Weg, um auf unerwartete oder ungewöhnliche Laufzeitbedingungen zu reagieren. Durch das Verständnis und die richtige Anwendung dieses Mechanismus können Entwickler robusteren und zuverlässigeren Code schreiben, der in der Lage ist, Fehlerbedingungen elegant zu behandeln.

6.2 Assertions

Assertions sind eine Methode, um während der Entwicklungsphase die Korrektheit von Annahmen im Code zu überprüfen. Ein Assertion-Statement prüft eine Bedingung, und wenn die Bedingung false ergibt, wird das Programm mit einer Fehlermeldung abgebrochen. Dies hilft Entwicklern, Fehler oder inkorrekte Annahmen frühzeitig im Entwicklungsprozess zu erkennen.

6.2.1 Verwendung von Assertions

In C++ wird die Assertion-Funktionalität über das Makro assert bereitgestellt, das im Header <cassert> (oder <assert.h> in C) definiert ist.

Ein einfaches Beispiel:

#include <cassert>

int main() {
    int x = 5;
    x += 5;

    // Dies wird erfolgreich durchlaufen, da x == 10
    assert(x == 10);

    x -= 5;

    // Dies wird einen Assertion-Fehler auslösen, da x != 10
    assert(x == 10);

    return 0;
}

Wenn eine Assertion fehlschlägt, wird standardmäßig eine Fehlermeldung mit der Datei und der Zeilennummer des fehlgeschlagenen assert angezeigt und das Programm wird beendet.

6.2.2 Wann sollte man Assertions verwenden?

6.2.3 Beachtenswerte Punkte

  1. Keine Nebenwirkungen: Das Argument des assert-Makros sollte keine Nebenwirkungen haben, da das Makro in Release-Builds entfernt wird und somit der darin enthaltene Code nicht ausgeführt wird.

  2. In Release-Builds deaktiviert: Standardmäßig wird assert in Release-Builds (wenn NDEBUG definiert ist) nicht ausgeführt. Das bedeutet, dass der Code in den Assertions in einer Release-Version des Programms nicht ausgeführt wird. Das ist beabsichtigt, da Assertions hauptsächlich während der Entwicklung nützlich sind.

6.2.4 TLDR;

Assertions in C++ sind ein wertvolles Werkzeug, um während der Entwicklungsphase die Korrektheit von Annahmen im Code zu überprüfen. Sie sollten jedoch nicht als Ersatz für reguläre Fehlerbehandlung oder zur Validierung von externen Eingaben verwendet werden. Stattdessen sind sie am besten geeignet, um sicherzustellen, dass der Code sich so verhält, wie der Entwickler es erwartet.