Namensräume
Varianten
Aktionen

RAII

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 

Resource Acquisition Is Initialization oder RAII ist eine C++-Programmiertechnik[1][2], die den Lebenszyklus einer Ressource, die vor der Verwendung erworben werden muss (allozierter Heap-Speicher, Ausführungsthread, offener Socket, offene Datei, gesperrter Mutex, Festplattenspeicher, Datenbankverbindung – alles, was in begrenzter Menge vorhanden ist), an den Lebenszyklus eines Objekts bindet.

RAII garantiert, dass die Ressource für jede Funktion verfügbar ist, die auf das Objekt zugreifen kann (Ressourcenverfügbarkeit ist ein Klasseninvariante, wodurch redundante Laufzeittests entfallen). Es garantiert auch, dass alle Ressourcen freigegeben werden, wenn der Lebenszyklus ihres steuernden Objekts endet, in umgekehrter Reihenfolge der Übernahme. Ebenso, wenn die Ressourcenübernahme fehlschlägt (der Konstruktor mit einer Ausnahme beendet wird), werden alle von voll ausgebildeten Member- und Basis-Subobjekten übernommenen Ressourcen in umgekehrter Reihenfolge der Initialisierung freigegeben. Dies nutzt Kernsprachmerkmale (Objektlebensdauer, Scope-Beendigung, Reihenfolge der Initialisierung und Stack-Unwinding), um Ressourcenlecks zu vermeiden und Exceptionsicherheit zu gewährleisten. Ein anderer Name für diese Technik ist Scope-Bound Resource Management (SBRM), nach dem grundlegenden Anwendungsfall, bei dem der Lebenszyklus eines RAII-Objekts aufgrund von Scope-Beendigung endet.

RAII kann wie folgt zusammengefasst werden:

  • Kapsle jede Ressource in einer Klasse, wobei
  • der Konstruktor die Ressource übernimmt und alle Klasseninvarianten herstellt oder eine Ausnahme auslöst, wenn dies nicht möglich ist,
  • der Destruktor die Ressource freigibt und niemals Ausnahmen auslöst;
  • benutze die Ressource immer über eine Instanz einer RAII-Klasse, die entweder
  • eine automatische Speicherklasse oder eine temporäre Lebensdauer selbst hat, oder
  • eine Lebensdauer hat, die durch die Lebensdauer eines automatischen oder temporären Objekts begrenzt ist.

Move-Semantik ermöglicht die Übertragung von Ressourcen und Eigentum zwischen Objekten, innerhalb und außerhalb von Containern und über Threads hinweg, während die Ressourcensicherheit gewährleistet wird.

(seit C++11)

Klassen mit Member-Funktionen wie open()/close(), lock()/unlock() oder init()/copyFrom()/destroy() sind typische Beispiele für Nicht-RAII-Klassen

std::mutex m;
 
void bad() 
{
    m.lock();             // acquire the mutex
    f();                  // if f() throws an exception, the mutex is never released
    if (!everything_ok())
        return;           // early return, the mutex is never released
    m.unlock();           // if bad() reaches this statement, the mutex is released
}
 
void good()
{
    std::lock_guard<std::mutex> lk(m); // RAII class: mutex acquisition is initialization
    f();                               // if f() throws an exception, the mutex is released
    if (!everything_ok())
        return;                        // early return, the mutex is released
}                                      // if good() returns normally, the mutex is released

[bearbeiten] Die Standardbibliothek

Die C++-Bibliotheksklassen, die ihre eigenen Ressourcen verwalten, folgen RAII: std::string, std::vector, std::jthread(seit C++20) und viele andere übernehmen ihre Ressourcen in Konstruktoren (die bei Fehlern Ausnahmen auslösen), geben sie in ihren Destruktoren frei (die niemals Ausnahmen auslösen) und erfordern keine explizite Bereinigung.

Darüber hinaus bietet die Standardbibliothek mehrere RAII-Wrapper zur Verwaltung benutzerdefinierter Ressourcen

(seit C++11)

[bearbeiten] Anmerkungen

RAII gilt nicht für die Verwaltung von Ressourcen, die nicht vor Gebrauch erworben werden: CPU-Zeit, Kernverfügbarkeit, Cache-Kapazität, Entropie-Pool-Kapazität, Netzwerkbandbreite, Stromverbrauch, Stack-Speicher. Für solche Ressourcen kann ein C++-Klassenkonstruktor die Verfügbarkeit der Ressource für die Dauer des Objektlebenszyklus nicht garantieren, und es müssen andere Mittel der Ressourcenverwaltung verwendet werden.

[bearbeiten] Externe Links

  1. RAII in Stroustrups C++ FAQ
  2. C++ Core Guidelines E.6 "Verwenden Sie RAII, um Lecks zu vermeiden"