C++-Programmierung/ Ausnahmebehandlung/ Werfen und fangen und weiterwerfen

Aus Wikibooks


In dem vorherigen Kapitel haben wir Ihnen eine Möglichkeit gezeigt, wie man auf Fehler reagieren kann: geht etwas schief, wird einfach ein Rückgabewert ungleich 0 zurückgeliefert. In kleinen Programmen mag das noch akzeptabel sein, aber in größeren Bibliotheken wie z. B. Qt oder boost ist das Einarbeiten in die Dokumentation doch recht mühsam, um alle Fehlerwerte korrekt zu behandeln. Außerdem können solche Fehlerwerte einfach übersehen werden, was die Fehlersuche massiv erschwert. C++ bietet einen speziellen Mechanismus, um Fehler zu behandeln: Ausnahmen (engl. exceptions). Dadurch wird die Fehlererkennung von der Fehlerbehandlung entkoppelt. Der resultierende Programmcode wird deutlich übersichtlicher und da Exceptions nicht so einfach ignoriert werden können, erleichtern sie auch die Fehlerdiagnose.

Ausnahmen werfen[Bearbeiten]

Die allgemeine Syntax zum Werfen (von engl. to throw) von Ausnahmen lautet:

Syntax:
throw «Objekt»;
«Nicht-C++-Code», »optional«

Theoretisch kann alles geworfen werden, auch ints oder andere primitive Datentypen. In der Regel wird jedoch ein Objekt der Klasse std::exception aus der Headerdatei stdexcept geworfen. Die Konstruktoren übernehmen meist eine Zeichenkette als Fehlermeldung, die später mit der Methode what() abgefragt werden kann.

Hier ein Beispiel, wie throw verwendet werden kann:

#include <stdexcept>
#include <iostream>

int flaeche(int breite, int laenge) throw(std::range_error){
    if ((breite <= 0) || (laenge <= 0))
        throw std::range_error("Breite oder Länge gleich 0 oder negativ");
    return (breite * laenge);
}

Das throw kann auch in der Methodendeklaration stehen und zeigt dann an, welche Art von Ausnahmen beim Aufruf ausgelöst werden können. Wichtig ist, dass die möglichen Ausnahmen in runden Klammern stehen und ggf. durch Kommata getrennt aufgeführt werden.

Ausnahmen fangen[Bearbeiten]

Um auf die Exceptions reagieren zu können (sie zu "fangen") braucht man zwei weitere Schlüsselwörter: try und catch. Beide leiten Blöcke in geschweiften Klammern ein. Auf jeden try-Block folgt mindestens ein catch-Block. Im sogenannten try-Block stehen Code-Abschnitte, die Ausnahmen auslösen können und im catch-Block werden diese "aufgefangen" und behandelt. Nach catch stehen die Arten von Exceptions, die in dem jeweiligen Block behandelt werden.

Syntax:
try{
    // kritischer Abschnitt
} catch («Exceptionklasse» »bezeichner«){
    // Ausnahmebehandlung
}
«Nicht-C++-Code», »optional«

Hier ist ein Programm, welches die flaeche()-Funktion aus dem Beispiel oben verwendet:

#include <stdexcept>
#include <ios>
#include <iostream>

using std::cout;
using std::cerr;
using std::cin;

int flaeche(int breite, int laenge) throw(range_error);

int main(){
    int a, b;
    // wenn ein wirklich schwerer Fehler auftritt soll cin eine Exception werfen
    cin.exceptions(cin.exceptions() | ios_base::badbit);
    cout << "Breite und Höhe eingeben: ";
    cin >> a >> b;
    try {
        cout << "Flächeninhalt: " << flaeche(a, b) << endl;
    } catch(const range_error& re){
        cerr << "Ungültige Eingaben: " << re.what() << endl;
        return 1;
    } catch(const ios_base::failure& f){
        cerr << "Schwerer Eingabefehler in cin:" << endl;
        cerr << f.what() << endl;
        return 2;
    }
    return 0;
}

Ausnahmen weiter werfen[Bearbeiten]

Oft kann es vorkommen, dass die auftretende Exception nicht vollständig behandelt werden kann. Dann ist es nützlich, die aufgetretene Ausnahme weiter zu werfen in der Hoffnung, dass irgendein Aufrufen sich darum kümmert. Die Syntax ist denkbar einfach:

Syntax:
try{
    // kritischer Abschnitt
} catch («Exceptionklasse» »bezeichner«){
    // teilweise Ausnahmebehandlung
    // "rethrow", Ausnahme erneut werfen
    throw;
}
«Nicht-C++-Code», »optional«