Menu
Coddy logo textTech

RAII in C++

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 16 von 104.

RAII (Resource Acquisition Is Initialization) ist ein grundlegendes C++-Idiom, bei dem die Ressourcenverwaltung an die Lebensdauer von Objekten gebunden ist. Die Idee ist einfach: Ressourcen im Konstruktor anfordern und sie im Destruktor freigeben.

Wenn ein Objekt erstellt wird, fordert es alle benötigten Ressourcen an. Wenn das Objekt seinen Gültigkeitsbereich verlässt, gibt sein Destruktor diese Ressourcen automatisch frei. Dies garantiert eine Bereinigung, selbst wenn Ausnahmen auftreten.

class FileHandler {
    std::FILE* file;
public:
    FileHandler(const char* filename) {
        file = std::fopen(filename, "r");  // Ressource erwerben
    }
    
    ~FileHandler() {
        if (file) std::fclose(file);       // Ressource freigeben
    }
};

Mit RAII vergessen Sie nie, Ressourcen freizugeben:

void processFile() {
    FileHandler handler("data.txt");  // Ressource belegt
    // Mit Datei arbeiten...
    // Wenn hier eine Exception geworfen wird, wird der Destruktor trotzdem ausgeführt!
}   // Ressource wird automatisch freigegeben

Smart Pointer sind das perfekte Beispiel für RAII in Aktion. Ein unique_ptr übernimmt den Besitz von Heap-Speicher in seinem Konstruktor und löscht diesen in seinem Destruktor. Sie haben RAII bereits verwendet, ohne es zu merken!

RAII gilt für jede Ressource: Speicher, Dateihandles, Netzwerkverbindungen, Mutexe oder Datenbankverbindungen. Durch das Kapseln von Ressourcen in Objekten stellt C++ eine deterministische Bereinigung sicher und eliminiert ganze Kategorien von Fehlern wie Leaks und verwaiste Handles.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen Verbindungsmanager erstellen, der RAII demonstriert, indem er den Lebenszyklus von netzwerkähnlichen Verbindungen automatisch verwaltet. Wenn eine Verbindung erstellt wird, soll sie sich "öffnen", und wenn sie den Gültigkeitsbereich verlässt, soll sie sich automatisch "schließen" — kein manuelles Aufräumen erforderlich!

Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:

  • Connection.h: Definieren Sie eine Connection-Klasse, die eine Verbindungsressource nach RAII-Prinzipien verwaltet. Die Klasse sollte Folgendes enthalten:
    • Ein privates Attribut connectionId (string), um die Verbindung zu identifizieren
    • Ein privates Attribut isOpen (bool), um den Verbindungsstatus zu verfolgen
    • Einen Konstruktor, der eine Verbindungs-ID entgegennimmt, isOpen auf true setzt und "Opening connection: <id>" ausgibt
    • Einen Destruktor, der prüft, ob die Verbindung offen ist, sie schließt, indem er isOpen auf false setzt, und "Closing connection: <id>" ausgibt
    • Eine Methode send(string message), die "[<id>] Sending: <message>" ausgibt, falls die Verbindung offen ist
    • Eine Methode getId(), die die Verbindungs-ID zurückgibt
  • main.cpp: Demonstrieren Sie, wie RAII die automatische Bereinigung sicherstellt, indem Sie eine Verbindungs-ID und eine Nachricht von der Eingabe lesen. Dann:
    • Erstellen Sie einen Gültigkeitsbereich mit geschweiften Klammern { }
    • Erstellen Sie innerhalb dieses Bereichs ein Connection-Objekt auf dem Stack mit der eingegebenen ID
    • Verwenden Sie die Verbindung, um die eingegebene Nachricht zu senden
    • Lassen Sie den Gültigkeitsbereich enden (die Verbindung sollte sich automatisch schließen)
    • Geben Sie nach dem Gültigkeitsbereich "Connection out of scope" aus

Das Schöne an RAII ist, dass Sie nicht daran denken müssen, die Verbindung zu schließen — der Destruktor erledigt das automatisch, wenn das Objekt den Gültigkeitsbereich verlässt. Dieses Muster verhindert Ressourcenlecks, selbst wenn in Ihrem Code etwas Unerwartetes passiert.

Binden Sie Ihre Header-Datei in main.cpp mit #include "Connection.h" ein.

Spickzettel

RAII (Resource Acquisition Is Initialization) ist ein C++-Idiom, bei dem die Ressourcenverwaltung an die Lebensdauer von Objekten gebunden ist. Ressourcen werden im Konstruktor angefordert und im Destruktor freigegeben.

Wenn ein Objekt seinen Gültigkeitsbereich verlässt, gibt sein Destruktor die Ressourcen automatisch frei, was eine Bereinigung garantiert, selbst wenn Ausnahmen auftreten:

class FileHandler {
    std::FILE* file;
public:
    FileHandler(const char* filename) {
        file = std::fopen(filename, "r");  // Ressource anfordern
    }
    
    ~FileHandler() {
        if (file) std::fclose(file);       // Ressource freigeben
    }
};

RAII gewährleistet eine automatische Bereinigung:

void processFile() {
    FileHandler handler("data.txt");  // Ressource angefordert
    // Mit Datei arbeiten...
    // Wenn eine Ausnahme ausgelöst wird, wird der Destruktor trotzdem ausgeführt!
}   // Ressource automatisch freigegeben

Smart Pointer wie unique_ptr sind Beispiele für RAII. Sie fordern Heap-Speicher im Konstruktor an und löschen ihn im Destruktor.

RAII gilt für jede Ressource: Speicher, Dateihandles, Netzwerkverbindungen, Mutexe oder Datenbankverbindungen. Es stellt eine deterministische Bereinigung sicher und eliminiert Fehler wie Leaks und hängende Handles.

Probier es selbst

#include <iostream>
#include <string>
#include "Connection.h"

using namespace std;

int main() {
    string connectionId;
    string message;
    
    // Eingabe lesen
    cin >> connectionId;
    cin.ignore();
    getline(cin, message);

    // TODO: Erstelle einen Scope mit geschweiften Klammern { }
    // Innerhalb des Scopes:
    //   - Erstelle ein Connection-Objekt auf dem Stack mit connectionId
    //   - Nutze die Verbindung, um die Nachricht zu senden
    // Lasse den Scope enden (der Destruktor wird automatisch aufgerufen)

    // TODO: Nachdem der Scope endet, gib "Connection out of scope" aus

    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung