Ausnahme Behandlungen mit try catch
Das zentrale Element der Fehlerbehandlung ist das Objekt der Exception. In C++ kann eine Exception jeden beliebigen Typ annehmen, also sowohl einen primitiven Datentyp wie int oder const char*, oder aber auch beliebige Klassen oder Strukturen.
throw - Exceptions werfen...
Um eine Exception auszulösen gibt es das Schlüsselwort throw (=werfen), welches gefolgt von einem Fehlerobjekt dieses in den Raum „wirft“, um damit einen Fehler zu signalisieren. Schauen wir uns dazu einmal ein einfaches Beispiel an:
Datei:
Quelldateien/main.cpp- #include <iostream> // std::cout, std::endl, std::cin
- #include <stdlib.h> // EXIT_SUCCESS
- #include "stdexcpt.h" // Standart Exeption Handler
-
- int main(void)
- {
- throw 123;
-
- std::cin.get();
- return EXIT_SUCCESS;
- }
Dieses Programm tut nichts weiter als ein Exception-Objekt vom Typ int mit dem Wert 123 in den Raum zu „werfen“, und nachdem wir noch nicht dafür gesorgt haben, dass es irgendwo wieder aufgefangen wird, kommt die Funktion std::terminate() ins Spiel, die in einem solchen Fall aufgerufen wird und das Programm mit einem Aufruf von std::abort() sofort beendet. Je nachdem welche Implementierung der Standardbibliothek man verwendet kann auch noch zusätzlich ein Hinweis auf den Grund des Beendens des Programms ausgegeben werden.
try/catch - ...und wieder fangen
Nachdem es aber wenig Sinn macht einfach Exceptions in den Raum zu werfen, und damit das Programm zu beenden, gibt es die Möglichkeit Exceptions aufzufangen um einerseits den Fehler zu behandeln und andererseits das Programm wieder normal, oder zumindest so gut wie es der aufgetretene Fehler erlaubt, weiterlaufen zu lassen.
Dabei kennzeichnen wir einen Block in dem Fehler auftreten können mit try und schreiben anschließend ein oder mehr catch-Blöcke, die jeweils einen Typ von Exception-Objekten auffangen können. Bei einem Fehler springt die Ausführung des Programms in den entsprechenden catch-Block und wird anschließend nach dem letzten catch-Block fortgesetzt.
Datei:
Quelldateien/main.cpp- #include <iostream> // std::cout, std::endl, std::cin
- #include <stdlib.h> // EXIT_SUCCESS
- #include "stdexcpt.h" // Standart Exeption Handler
-
- int main(void)
- {
- try
- {
- throw 123;
- //throw "Da stimmt was nicht...";
- //char* memory = new char[0x7fffffff]; // Bereich ist definitiv zu groß
- //throw 1.3f;
- }
- catch (int e)
- {
- std::cout << "int abgefangen: " << e << std::endl;
- }
- catch (char const* e)
- {
- std::cout << "char const* abgefangen: " << e << std::endl;
- }
- catch (std::bad_alloc& e)
- {
- std::cout << "Speicheranforderung (new) fehlgeschlagen: " << e.what() << std::endl;
- }
- catch(...) // Ellipsis-Handler
- {
- std::cout << "Unbekannter Fehler" << std::endl;
- }
-
- std::cin.get();
- return EXIT_SUCCESS;
- }
An diesem nicht gerade sinnvollen Code kann man sehr gut das Verhalten von Exceptions beobachten und damit experimentieren.
Eine Besonderheit stellt noch der letzte Handler dar, bei dem es sich um einen sogenannten Ellipsis-Handler (catch(…)) handelt. Dieser kann jeden beliebigen Typ von Exception fangen, sollte aber aus diesem Grund auch wirklich nur in Ausnahmesituationen und ansonsten vermieden werden. Im Beispiel wird er mit throw 1.3f; aufgerufen da wir keinen catch(float e){...} Block für denn Datentyp float notiert haben.