Fehlerbehandlung in C++: try/catch und fortgeschrittene Techniken

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Fortgeschrittene Fehlerbehandlung in C++: von try/catch zu industriellen Praktiken



Fehlerbehandlung ist einer der Eckpfeiler der industriellen Programmierung. In C++ steht dem Entwickler nicht nur der klassische Mechanismus try/catch zur Verfügung, sondern ein ganzes Arsenal an fortgeschrittenen Techniken: von RAII bis zu Garantien der Ausnahmesicherheit. In diesem Artikel werden wir analysieren, wie man zuverlässigen C++ Code schreibt, der Fehler korrekt behandelt, keine Ressourcen verliert und lesbar bleibt.



1. Grundlagen und Standardfallen von try/catch



Die grundlegende Syntax ist jedem bekannt:



#include <iostream>#include <stdexcept>

void dangerousFunction(int value) { if (value < 0) { throw std::invalid_argument("Value must be non-negative"); } // ... Arbeit mit value}

int main() { try { dangerousFunction(-5); } catch (const std::invalid_argument& e) { std::cerr << "Error: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "Generic error: " << e.what() << std::endl; } catch (...) { std::cerr << "Unknown exception caught" << std::endl; } return 0;}


Wichtige Punkte:

  • Fangen Sie per Referenz — catch (const std::exception& e) vermeidet Objekt-Slicing.
  • Die Reihenfolge der catch-Blöcke ist wichtig: zuerst spezifischere Ausnahmen, dann allgemeine.
  • Verwenden Sie catch (...) nicht übermäßig — es versteckt alle Fehler, einschließlich kritischer (z.B. std::bad_alloc).
  • Werfen Sie niemals Ausnahmen aus Destruktoren — dies führt zu undefiniertem Verhalten (normalerweise zu einem Programmabsturz).


2. RAII als Alternative zu try/catch für die Ressourcenverwaltung



RAII (Resource Acquisition Is Initialization) ist das zentrale Muster in C++, das Ausnahmen sicher macht. Die Idee: Eine Ressource wird im Konstruktor erworben und im Destruktor freigegeben. Wenn eine Ausnahme auftritt, werden die Destruktoren aller erstellten Objekte automatisch aufgerufen (Stack Unwinding).



#include <fstream>#include <vector>#include <stdexcept>

void processFile(const std::string& filename) { std::ifstream file(filename); // RAII: Datei wird im Konstruktor geöffnet if (!file.is_open()) { throw std::runtime_error("Cannot open file: " + filename); }

std::vector<int> data; int value; while (file >> value) { data.push_back(value); } // Der Destruktor von file schließt die Datei automatisch, // selbst wenn eine Ausnahme auftritt (z.B. bad_alloc bei push_back)}


Vorteile von RAII gegenüber manuellem try/catch:

  • Keine Notwendigkeit, finally-Blöcke zu schreiben — Destruktoren garantieren die Bereinigung.
  • Der Code wird linearer und lesbarer.
  • Ausnahmen führen nicht zu Speicherlecks, Verlust von Dateideskriptoren usw.


3. Garantien der Ausnahmesicherheit



In C++ werden üblicherweise drei Sicherheitsstufen für Funktionen unterschieden:



  • No-throw guarantee — die Funktion wirft niemals Ausnahmen. Wird mit noexcept markiert.
  • Strong guarantee — wenn eine Ausnahme auftritt, bleibt der Programmzustand unverändert (atomare Operation).
  • Basic guarantee — bei einer Ausnahme treten keine Ressourcenlecks auf, Objekte bleiben in einem konsistenten Zustand, ihr Wert kann sich jedoch ändern.


Beispiel mit strong guarantee (Copy-and-Swap-Idiom):



#include <algorithm>  // für std::swap#include <vector>#include <stdexcept>

class SafeVector { std::vector<int> data_;public: void push_back(int value) { // 1. Erstell

Blogs

Buchempfehlungen