Man kann (muß aber nicht) hinter der Parameterliste einer
Funktionsdeklaration angeben, ob und wenn ja welche Ausnahmen von
dieser Funktion geworfen werden:
void up( int i, int j ) throw( int, CFahrzeug );
Hier wird zugesichert, daß up() nur Ausnahmen vom Typ int
oder CFahrzeug (oder davon abgeleiteten Klassen) wirft.
Dagegen garantiert die Deklaration:
void up2( int i, int j ) throw();
daß die Funktion überhaupt keine Ausnahme wirft.
Der Compiler kann dies zur Übersetzungszeit gar nicht oder zumindest nicht in jedem Fall kontrollieren, weil er nicht alle direkt oder indirekt aufgerufenen Unterprogramme kennt, also auch nicht kontrollieren kann, was darin alles geworfen werden könnte.
Wird eine Funktion an mehreren Stellen deklariert, dann müssen überall die selben Ausnahmen gelistet werden.
Macht man gar keine Angaben über die geworfenen Ausnahmen:
void up3( int i, int j );
dann darf die Funktion werfen, was sie will.
Will man eine virtuelle Elementfunktion überschreiben, dann darf die Überschreibung die Liste der geworfenen Ausnahmen einengen, aber nicht erweitern.
Wenn für Funktion eine Liste der möglichen Ausnahmen spezifiziert ist,
sie aber trotzdem etwas anderes zu werfen
versucht, dann wird zur Laufzeit die Funktion std::unexpected()
aufgerufen, die normalerweise std::terminate()
aufruft, die
wiederum im Standardfall mit abort() das laufende Programm beendet.
Man hat mehrere Möglichkeiten, dieses Verhalten zu ändern:
std::unexpected()
kann durch einen Aufruf
von void set_unexpected( void(*)() )
auf eine eigene Funktion
umgebogen werden. Diese eigene Funktion (keine Parameter, keine
Rückgabewerte) sollte je nach Bedarf den Fehler protokollieren, und
dann durch einen Aufruf von terminate()
das Programm beenden.
Die übergebene Funktion darf nicht zurückkehren, und keine Ausnahme werfen.
Anmerkung: Selbst wenn man gleich am Anfang von main() mit
set_unexpected()
einen eigenen Handler für diesen Fall
installiert, kann es trotzdem schon vor dem Eintritt in das
Hauptprogramm zu einer unbehandelten Ausnahme kommen, und zwar wenn
eine solche Ausnahme in einem Konstruktor auftritt, der für ein
globales Objekt aufgerufen wird. Diese Aufrufe finden vor dem Eintritt
in main() statt!
void set_terminate( void(*)() )
eine eigene Funktion angeben,
die anstelle von terminate() aufgerufen wird.
Auch hier bekommt die übergebene Funktion keine Parameter, liefert keinen Rückgabewert, darf nicht zurückkehren und keine Ausnahme werfen.
bad_exception
(siehe
dazu Ausnahmen der Standardbibliothek)
an. Dann wird
bei Auftreten einer nicht angegebenen Ausnahme automatisch vom
Laufzeitsystem die tatsächlich auftretende Ausnahme auf eine vom Typ
bad_exception
umgesetzt, und diese kann von einem aufrufenden
Programmteil wie gewohnt gefangen und behandelt werden. Allerdings
geht damit jede
Information über den Ort und die Art des aufgetretenen Fehlers
verloren.
AnyWare@Wachtler.de