Exceptions: Ausnahmen mit Fußspuren

Um das Thema der Ausnahmebehandlung (auch als Exceptions bekannt), sind schon mehrmals große Kriege entbrannt. Am Ende geht es immer um die Frage:

Wie viel Overhead wird durch Exceptions erzeugt?

Denn im “guten alten C” kommt man schließlich ohne dieses Konstrukt aus. Meine Meinung dazu ist bekannt:
Exceptions sind eine wichtige Sprachbereicherung, solange man es nicht übertreibt.


Das große Problem mit C++ und seinen Exceptions entstand leider zu einer sehr ungünstigen Zeit, die lange vergangen und großteils auch überwunden ist. Trotzdem halten sich Mythen aus jenen Tagen bis heute und werden durch Wanderprediger immer wieder aufgefrischt.

Schuld sind Windows und X86!

Denn als mit WIN32 Structured Exceptions auf der Windows Architektur standardisiert wurden und Compiler auf dieser Plattform sich an den vorgeschriebenen Standard halten mussten, war die Welt noch sehr C-orientiert. Programme und Bibliotheken kennen (bis heute) im Grunde genommen nur flache Funktionen, die sich gegenseitig aufrufen … also genau das, was auch der Prozessor sieht.

Exceptions wurden daher als Teil einer jeden Funktion implementiert. Ein try { ... } catch(...) { ... } führt demnach zu einigen Prozessor-Anweisungen, die den Fall einer Exception vorbereiten müssen, um im Bedarfsfall den Programmfluss entsprechend umzuleiten.

Schlimmer noch: Auch ohne try/catch muss bei jedem Funktionsaufruf die Möglichkeit beachtet werden, dass aus der Funktion “irgendwie” eine Exception zurückkommt.

Hier lehnten sich C Programmierer gegen das neue Konzept auf und fanden Beispiele, wo mit klassischen Status-Return-Codes nur eine Hand voll, mit Exception aber ein Vielfaches an Instruktionen beim Übersetzen erzeugt wurde.

Also JA, damals führte die Nutzung von Exception zur Erzeugung von großen Codeblöcken, die aber nur im Ausnahmefall wirklich notwendig waren. In Summe ergibt sich also ein messbarer Performanceabfall.

Auf anderen Plattformen wie Linux mit dem GCC entwickelte man dieses Konzept weiter und änderte die Art, wie Exception-Code generiert wird. Denn bekanntlich schreibt der C++ Standard keine besondere Implementierung vor, im Gegenteil, man muss sogar damit rechnen, dass jeder Compiler den Code anders übersetzt.

Und so schaffte es Microsoft erst mit der 64-bit Architektur, ein besseres Exception-Modell einzuführen, während auf der 32-bit Seite aus Gründen der Kompatibilität das alte Model (zumindest teilweise) weiter zum Einsatz kommt.

Die Idee:
Exception-Code ist von regulärem Code separiert und vieles an “neuer Magie” steckt im “Werfen” einer Ausnahme. Hier werden dann unterschiedliche Code-Tabellen benutzt, die das Zurückwandern durch den Callstack (auch als Stack-Unwinding bekannt) bis zum nächsten catch Block ermöglichen.

Während also früher jede Funktion Exceptions entgegennehmen und selbst wieder weiterleiten musste, findet dieser Part heute außerhalb der Funktion in jenen Tabellen und zusätzlichen Hilfscode statt der zwischen den Funktionen (oder auch ganz wo anders) liegt.

Damit wird die reguläre Ausführung von Programmcode genau so schnell wie C Code (teilweise sogar schneller, weil keine Status-Return-Values notwendig sind). Und wenn es zum throw kommen sollte, wird der Stack durch externen Code zurückgerollt.

Schließlich sind Exceptions ja “Ausnahmen” und nicht die Regel. Sie werden also nur im Notfall und damit hoffentlich eher selten ausgeführt, womit diese Optimierung allen korrekten Ausführungspfaden Geschwindigkeitsvorteile verschafft.


Heute kann man daher nicht mehr wie früher argumentieren, Exception würden die Code-Ausführung verlangsamen.

Und es freut mich sehr, dass selbst damit die Weiterentwicklung nicht stehen bleibt. Kürzlich sah ich erst, dass das Exception-Modell ständig weiter optimiert und verbessert wird.

So lange also Programmierer nicht den Fehler machen, Exceptions für reguläre Ausführungszweige zu missbrauchen, so lange sind und bleiben Exceptions die heute beste Form der Fehlerbehandlung.

Und wer sich für die neuesten Entwicklungen in Sachen Exceptions beim MSVC interessiert, der kann hier weiterlesen:
Making C++ Exception Handling Smaller On x64