In der klassischen C-Programmierung werden zur Fehler- bzw. Ausnahmebehandlung Funktionen verwendet, die im Resultat oder in einem Parameter Informationen über eine aufgetretene Ausnahme liefern.

Dies erfordert nach jedem Funktionsaufruf mit potentieller Fehlermöglichkeit eine Auswertung der Ausnahmeinformation.

Wünschenswert erscheint ein Konstrukt, durch welches eine gebündelte Folge von Anweisungen sukzessive ausgeführt wird und sobald darin an irgendeiner Stelle eine Ausnahme auftritt, diese Ausnahme angemessen behandelt wird.

Beispiel: z = Arc sin(1/x)

  1. Lies Fließkommazahl in Variable x ein.
  2. Berechne Kehrwert von x und weise diesen der Variablen y zu.
  3. Berechne Arcus Sinus von y und weise diesen der Variablen z zu.
  4. Gib den Inhalt von z aus.

Zumindest in jedem der ersten drei Schritte kann es zu Fehlern bzw. Ausnahmen kommen (Eingabefehler, Division durch Null, Betrag des Arguments von Arc sin zu groß).

Klassische Implementation in C:

if (ReadFloat(&x))   // ReadFloat liest Fliesskommazahl ein
 if (Kehrwert(&y,x)) // Kehrwert weist y den Kehrwert von x zu
  if (y>=-1 && y<=+1)
  {z = asin(y));
   printf("%f",z);}
...

Verbesserte Möglichkeiten in C++

Zunächst müssen die aufgerufenen Funktionen eine aufgetretene Ausnahme wie eine Funktionsstörung auf einem gesonderten Weg melden können (vgl. Not-Aus Schalter). Dies erfordert ein gegenüber ANSI-C neues Sprachkonstrukt.

Sobald eine Ausnahme gemeldet wird, dürfen die in der Sequenz folgenden Anweisungen nicht mehr ausgeführt werden. Statt dessen ist diese Ausnahme wie eine Störung zu behandeln.

Zum obigen Beispiel:

Wenn für x eine Null eingegeben wurde (1.), tritt bei der Berechnung des Kehrwertes (2.) eine Ausnahme auf - Division durch Null. Dann ist es völlig sinnlos, den Arc sin (3.) berechnen zu lassen. Genauso wenig macht es Sinn, den Inhalt von z ausgeben zu lassen (4.).

In C++ Syntax sieht dies folgendermaßen aus:

...
try // Buendelung der Anweisungen mit gemeinsamer Ausnahmebehandlung
{
  cin >> x;
  y = Kehrwert(x);
  z = Arcsin(y);
  cout << z << endl;
}
catch(...) // Jegliche Ausnahme wird behandelt
{
 cout << "Ausnahme aufgetreten." << endl;
} ...

try und catch sind die für die Ausnahmebehandlung erforderlichen Schlüsselwörter in C++. Die geschweiften Klammern dahinter sind zwingend erforderlich, auch bei einer Einzelanweisung.

Statt der drei Punkte hinter catch wird zumeist der Typ einer Ausnahmeinformation, kurz der Ausnahmetyp, zusammen mit einer Ausnahmevariablen (Objekt, Instanz) angegeben. Dann werden an dieser Stelle auch nur Ausnahmen dieses Typs behandelt.

Beispiel:

catch (int id) // Es werden nur Ausnahmen des Typs int behandelt.
{
 cout << "Ausnahmecode " << id << " aufgetreten." << endl;
}

Falls z.B. eine Ausnahme des Typs float eintritt, wird sie an dieser Stelle nicht behandelt.

Wo kommen die Ausnahmen als Störungsmeldungen her?

Antwort: Sie werden geworfen.

Eine Funktion, die eine Ausnahme meldet (nicht bearbeitet!!!), wirft diese aus.

Beispiel:

double Kehrwert(double x) throw(int// Kehrwert meldet int-Ausnahmen
{
 if (x==0.0throw 1// Ausnahme melden
 return 1/x;
}

Vorsicht!!!
Der Ausnahmetyp, hier int, hat nichts mit dem Parametertyp oder dem Resultatstyp zu tun. Er ist der Typ für die Ausnahmeinformation.

Für den Ausnahmetyp gibt es in C++ keine Einschränkung. Er kann also ebenso double, ein String, irgendein Array, ein struct oder noch besser eine Klasse (OOP) sein.

Die folgende Sequenz behandelt die Ausnahme "Division durch Null". Im Ausnahmefall wird der y-Inhalt nicht ausgegeben. Deshalb sollte diese Ausgabe nicht hinter der Fehlerbehandlung stehen.

try
{
 y = Kehrwert(x); // Hier kann eine Ausnahme gemeldet werden.
 cout << "Der Kehrwert von " << x << " ist " << y << ".\n" << endl;
}
catch(int id)
{
 cout << "Ausnahme " << id << " aufgetreten." << endl;
}
... // Hier folgen weitere Anweisungen.

Ein try-catch-Konstrukt ist eine Anweisungssequenz. Im Allgemeinen folgen dahinter weitere Anweisungen, die anschließend ausgeführt werden.

Komplette Beispiele folgen.