Was ist mit Resource Acquisition is Initialization (RAII) gemeint?

Lesezeit: 11 Minuten

Was ist mit Resource Acquisition is Initialization RAII gemeint
John

Was ist mit Resource Acquisition is Initialization (RAII) gemeint?

Was ist mit Resource Acquisition is Initialization RAII gemeint
der_mandrill

Es ist ein wirklich schrecklicher Name für ein unglaublich mächtiges Konzept und vielleicht eines der wichtigsten Dinge, die C++-Entwickler vermissen, wenn sie zu anderen Sprachen wechseln. Es gab eine gewisse Bewegung, um zu versuchen, dieses Konzept in umzubenennen Bereichsgebundene Ressourcenverwaltungobwohl es sich anscheinend noch nicht durchgesetzt hat.

Wenn wir „Ressource“ sagen, meinen wir nicht nur Speicher – es können Datei-Handles, Netzwerk-Sockets, Datenbank-Handles, GDI-Objekte sein … Kurz gesagt, Dinge, die wir nur begrenzt zur Verfügung haben und daher benötigen ihre Verwendung kontrollieren. Der Aspekt „Scope-bound“ bedeutet, dass die Lebensdauer des Objekts an den Gültigkeitsbereich einer Variablen gebunden ist, sodass der Destruktor die Ressource freigibt, wenn die Variable den Gültigkeitsbereich verlässt. Eine sehr nützliche Eigenschaft davon ist, dass es für eine größere Ausnahmesicherheit sorgt. Vergleichen Sie zum Beispiel dies:

RawResourceHandle* handle=createNewResource();
handle->performInvalidOperation();  // Oops, throws exception
...
deleteResource(handle); // oh dear, never gets called so the resource leaks

Mit dem RAII eins

class ManagedResourceHandle {
public:
   ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
   ~ManagedResourceHandle() {delete rawHandle; }
   ... // omitted operator*, etc
private:
   RawResourceHandle* rawHandle;
};

ManagedResourceHandle handle(createNewResource());
handle->performInvalidOperation();

In diesem letzteren Fall werden die lokalen Variablen zerstört, wenn die Ausnahme ausgelöst und der Stapel entladen wird, wodurch sichergestellt wird, dass unsere Ressource bereinigt wird und nicht leckt.

  • @the_mandrill: Ich habe dieses Programm auf ideone.com/1Jjzuc ausprobiert. Aber es gibt keinen Destruktoraufruf. Die tomdalling.com/blog/software-design/… besagt, dass C++ garantiert, dass der Destruktor von Objekten auf dem Stapel aufgerufen wird, selbst wenn eine Ausnahme ausgelöst wird. Also, warum wurde der Destruktor hier nicht ausgeführt? Ist meine Ressource durchgesickert oder wird sie niemals freigegeben oder freigegeben?

    – Destruktor

    20. August 2015 um 16:40 Uhr

  • Eine Ausnahme wird ausgelöst, aber Sie fangen sie nicht ab, sodass die Anwendung beendet wird. Wenn Sie mit try { } catch () {} umbrechen, funktioniert es wie erwartet: ideone.com/xm2GR9

    – der_Mandrill

    21. August 2015 um 10:41 Uhr

  • Nicht ganz sicher, ob Scope-Bound ist hier die beste Namenswahl seit Speicherklassenbezeichnern zusammen mit der Geltungsbereich bestimmt die Speicherdauer einer Entität. Die Einschränkung auf den Umfang ist vielleicht eine nützliche Vereinfachung, aber nicht 100% genau

    – Klick mich

    12. April 2018 um 8:53 Uhr


  • Aber wie erklärt man RA is initialization im Originalnamen? Was ich unter RAII verstehe, ist, dass es in der Verantwortung jedes Objekts liegt, sich um seine Löschung zu kümmern, sobald es außerhalb des Geltungsbereichs liegt. Für mich passt das nicht zusammen is initialization weil alles mit dem Destruktor zusammenhängt. Ich bin immer noch verwirrt von diesem Idiomnamen.

    – nowox

    11. November 2020 um 12:49 Uhr

  • “… die wichtigsten Dinge, die C++-Entwickler vermissen …” Ist das nicht ähnlich wie try-with-resources in Java? Es scheint das gleiche Problem zu lösen, und ich sehe keinen Vor- oder Nachteil von RAII im Vergleich zu Javas Lösung.

    – marc.guenther

    17. Dezember 2021 um 15:58 Uhr

Was ist mit Resource Acquisition is Initialization RAII gemeint
Peter Török

Dies ist eine Programmiersprache, die kurz bedeutet, dass Sie

  • eine Ressource in eine Klasse kapseln (deren Konstruktor normalerweise – aber nicht notwendigerweise** – die Ressource erwirbt und ihr Destruktor sie immer freigibt)
  • Verwenden Sie die Ressource über eine lokale Instanz der Klasse*
  • Die Ressource wird automatisch freigegeben, wenn das Objekt den Gültigkeitsbereich verlässt

Dies garantiert, dass alles, was passiert, während die Ressource verwendet wird, letztendlich freigegeben wird (ob durch normale Rückgabe, Zerstörung des enthaltenden Objekts oder eine ausgelöste Ausnahme).

Es ist eine weit verbreitete bewährte Methode in C++, da es nicht nur eine sichere Methode zum Umgang mit Ressourcen darstellt, sondern auch Ihren Code viel sauberer macht, da Sie den Fehlerbehandlungscode nicht mit der Hauptfunktionalität mischen müssen.

* Aktualisieren: “Lokal” kann eine lokale Variable oder eine nichtstatische Mitgliedsvariable einer Klasse bedeuten. Im letzteren Fall wird die Mitgliedsvariable mit ihrem Besitzerobjekt initialisiert und zerstört.

** Update2: Wie @sbi betonte, kann die Ressource – obwohl sie oft innerhalb des Konstruktors zugewiesen wird – auch außerhalb zugewiesen und als Parameter übergeben werden.

  • AFAIK, das Akronym bedeutet nicht, dass sich das Objekt auf einer lokalen (Stack-)Variablen befinden muss. Es könnte eine Mitgliedsvariable eines anderen Objekts sein, wenn also das ‘haltende’ Objekt zerstört wird, wird auch das Mitgliedsobjekt zerstört und die Ressource wird freigegeben. Tatsächlich denke ich, dass das Akronym ausdrücklich nur bedeutet, dass es kein gibt open()/close() Methoden zum Initialisieren und Freigeben der Ressource, nur der Konstruktor und der Destruktor, sodass das „Halten“ der Ressource nur die Lebensdauer des Objekts ist, unabhängig davon, ob diese Lebensdauer vom Kontext (Stack) oder explizit (dynamische Zuweisung) behandelt wird.

    – Javier

    23. Februar 2010 um 20:51 Uhr

  • Eigentlich sagt nichts, dass die Ressource im Konstruktor erworben werden muss. Dateistreams, Strings und andere Container tun das, aber die Ressource könnte es genauso gut sein bestanden an den Konstruktor, wie es normalerweise bei intelligenten Zeigern der Fall ist. Da Ihre Antwort am meisten positiv bewertet wurde, möchten Sie dies möglicherweise beheben.

    – sbi

    8. Oktober 2012 um 20:59 Uhr

  • Es ist kein Akronym, sondern eine Abkürzung. IIRC die meisten Leute sprechen es “ar ey ay ay” aus, also qualifiziert es sich nicht wirklich für ein Akronym wie sagen wir DARPA, das DARPA statt buchstabiert wird. Außerdem würde ich sagen, dass RAII eher ein Paradigma als eine bloße Redewendung ist.

    – dtech

    5. August 2013 um 10:24 Uhr

  • @ Peter Torok: Ich habe es versucht ideone.com/1Jjzuc dieses Programm. Aber es gibt keinen Destruktoraufruf. Die tomdalling.com/blog/software-design/… besagt, dass C++ garantiert, dass der Destruktor von Objekten auf dem Stack aufgerufen wird, selbst wenn eine Ausnahme ausgelöst wird. Also, warum wurde der Destruktor hier nicht ausgeführt? Ist meine Ressource durchgesickert oder wird sie niemals freigegeben oder freigegeben?

    – Destruktor

    20. August 2015 um 16:35 Uhr

  • In diesem Beispiel wird die Ausnahme nicht abgefangen, sodass das Programm sofort beendet wird. Wenn Sie die Ausnahme abfangen, wird der Destruktor aufgerufen, wenn der Stapel entladen wird.

    – der_Mandrill

    12. November 2020 um 16:36 Uhr

1647280214 476 Was ist mit Resource Acquisition is Initialization RAII gemeint
sbi

„RAII“ steht für „Resource Acquisition is Initialization“ und ist eigentlich eine ziemlich falsche Bezeichnung, da es sich nicht um eine Ressource handelt Erwerb (und die Initialisierung eines Objekts) betrifft, aber loslassen die Ressource (mittels Zerstörung eines Objektes).
Aber RAII ist der Name, den wir bekommen haben, und er bleibt.

Im Kern bietet das Idiom das Einkapseln von Ressourcen (Speicherblöcke, offene Dateien, entsperrte Mutexe, was auch immer) in lokale, automatische Objekteund dass der Destruktor dieses Objekts die Ressource freigibt, wenn das Objekt am Ende des Bereichs zerstört wird, zu dem es gehört:

{
  raii obj(acquire_resource());
  // ...
} // obj's dtor will call release_resource()

Natürlich sind Objekte nicht immer lokale, automatische Objekte. Sie könnten auch Mitglieder einer Klasse sein:

class something {
private:
  raii obj_;  // will live and die with instances of the class
  // ... 
};

Wenn solche Objekte Speicher verwalten, werden sie oft als “intelligente Zeiger” bezeichnet.

Davon gibt es viele Variationen. Beispielsweise stellt sich in den ersten Codeschnipseln die Frage, was passieren würde, wenn jemand kopieren wollte obj. Der einfachste Ausweg wäre, das Kopieren einfach zu verbieten. std::unique_ptr<>ein intelligenter Zeiger, der Teil der Standardbibliothek sein soll, wie sie vom nächsten C++-Standard vorgestellt wird, tut dies.
Ein weiterer solcher intelligenter Zeiger, std::shared_ptr verfügt über “geteiltes Eigentum” an der Ressource (einem dynamisch zugewiesenen Objekt), die es besitzt. Das heißt, es kann frei kopiert werden und alle Kopien beziehen sich auf dasselbe Objekt. Der intelligente Zeiger verfolgt, wie viele Kopien sich auf dasselbe Objekt beziehen, und löscht es, wenn die letzte zerstört wird.
Eine dritte Variante wird von vorgestellt std::auto_ptr Dies implementiert eine Art Move-Semantik: Ein Objekt gehört nur einem Zeiger, und der Versuch, ein Objekt zu kopieren, führt (durch Syntax-Hacking) dazu, dass der Besitz des Objekts auf das Ziel der Kopieroperation übertragen wird.

  • std::auto_ptr ist eine veraltete Version von std::unique_ptr. std::auto_ptr eine Art simulierte Bewegungssemantik, soweit es in C++98 möglich war, std::unique_ptr verwendet die neue Move-Semantik von C++11. Eine neue Klasse wurde erstellt, da die Move-Semantik von C++11 expliziter ist (erfordert std::move außer von temporär), während es für jede Kopie von non-const in voreingestellt war std::auto_ptr.

    – Jan Hudec

    5. August 2013 um 9:40 Uhr

  • @JiahaoCai: Vor vielen Jahren (im Usenet) hat Stroustrup selbst das gesagt.

    – sbi

    20. Januar 2020 um 18:49 Uhr

Die Lebensdauer eines Objekts wird durch seinen Geltungsbereich bestimmt. Manchmal müssen wir jedoch, oder es ist nützlich, ein Objekt zu erstellen, das unabhängig von dem Bereich lebt, in dem es erstellt wurde. In C++ der Operator new wird verwendet, um ein solches Objekt zu erstellen. Und um das Objekt zu zerstören, der Betreiber delete kann verwendet werden. Vom Bediener erstellte Objekte new werden dynamisch allokiert, d.h. allokiert im dynamischen Speicher (auch genannt Haufen oder kostenlos speichern). Also ein Objekt, das von erstellt wurde new wird weiter existieren, bis es explizit zerstört wird mit delete.

Einige Fehler, die bei der Verwendung auftreten können new und delete sind:

  • Durchgesickertes Objekt (oder Speicher): mit new ein Objekt zuordnen und vergessen delete das Objekt.
  • Vorzeitig löschen (oder hängende Referenz): Halten eines anderen Zeigers auf ein Objekt, delete das Objekt, und verwenden Sie dann den anderen Zeiger.
  • Doppelt löschen: versuchen delete ein Objekt zweimal.

Im Allgemeinen werden Bereichsvariablen bevorzugt. RAII kann jedoch alternativ dazu verwendet werden new und delete ein Objekt unabhängig von seinem Geltungsbereich zum Leben erwecken. Eine solche Technik besteht darin, den Zeiger auf das Objekt zu nehmen, das auf dem Heap zugewiesen wurde, und es in a zu platzieren Handle/Manager-Objekt. Letzteres hat einen Destruktor, der sich um die Zerstörung des Objekts kümmert. Dadurch wird sichergestellt, dass das Objekt für alle Funktionen verfügbar ist, die darauf zugreifen möchten, und dass das Objekt zerstört wird, wenn die Lebensdauer der Objekt behandeln endet, ohne dass eine explizite Bereinigung erforderlich ist.

Beispiele aus der C++-Standardbibliothek, die RAII verwenden, sind std::string und std::vector.

Betrachten Sie diesen Codeabschnitt:

void fn(const std::string& str)
{
    std::vector<char> vec;
    for (auto c : str)
        vec.push_back(c);
    // do something
}

Wenn Sie einen Vektor erstellen und Elemente dorthin schieben, kümmern Sie sich nicht darum, solche Elemente zuzuweisen oder freizugeben. Der Vektor verwendet new Platz für seine Elemente auf dem Heap zuzuweisen, und delete um diesen Raum freizugeben. Sie als Benutzer von vector kümmern sich nicht um die Implementierungsdetails und vertrauen darauf, dass vector keine Daten verliert. In diesem Fall ist der Vektor der Objekt behandeln seiner Elemente.

Andere Beispiele aus der Standardbibliothek, die RAII verwenden, sind std::shared_ptr, std::unique_ptrund std::lock_guard.

Ein anderer Name für diese Technik ist SBRMkurz für Bereichsgebundene Ressourcenverwaltung.

1647280214 929 Was ist mit Resource Acquisition is Initialization RAII gemeint
Dennis

Das Buch C++ Programming with Design Patterns Revealed beschreibt RAII als:

  1. Erwerb aller Ressourcen
  2. Ressourcen nutzen
  3. Ressourcen freigeben

Woher

  • Ressourcen werden als Klassen implementiert, und alle Zeiger haben Klassen-Wrapper um sich herum (was sie zu intelligenten Zeigern macht).

  • Ressourcen werden durch Aufrufen ihrer Konstruktoren erworben und implizit (in umgekehrter Reihenfolge des Erwerbs) durch Aufrufen ihrer Destruktoren freigegeben.

  • @Brandin Ich habe meinen Beitrag so bearbeitet, dass sich die Leser auf den Inhalt konzentrieren, der wichtig ist, anstatt über die Grauzone des Urheberrechts zu diskutieren, was eine faire Verwendung darstellt.

    – Denis

    29. Mai 2016 um 13:33 Uhr

1647280215 629 Was ist mit Resource Acquisition is Initialization RAII gemeint
Mohammed Moridi

Eine RAII-Klasse besteht aus drei Teilen:

  1. Die Ressource wird im Destruktor aufgegeben
  2. Instanzen der Klasse werden dem Stapel zugeordnet
  3. Die Ressource wird im Konstruktor erfasst. Dieser Teil ist optional, aber üblich.

RAII steht für „Resource Acquisition is initialization“. Im „Ressourcenerwerb“-Teil von RAII beginnen Sie etwas, das später beendet werden muss, wie zum Beispiel:

  1. Öffnen einer Datei
  2. Etwas Speicher zuweisen
  3. Erwerb einer Sperre

Der Teil „is initialization“ bedeutet, dass die Übernahme innerhalb des Konstruktors einer Klasse erfolgt.

https://www.tomdalling.com/blog/software-design/resource-acquisition-is-initialisation-raii-explained/

  • @Brandin Ich habe meinen Beitrag so bearbeitet, dass sich die Leser auf den Inhalt konzentrieren, der wichtig ist, anstatt über die Grauzone des Urheberrechts zu diskutieren, was eine faire Verwendung darstellt.

    – Denis

    29. Mai 2016 um 13:33 Uhr

1647280215 190 Was ist mit Resource Acquisition is Initialization RAII gemeint
Dmitri Pawlow

Die manuelle Speicherverwaltung ist ein Albtraum, den Programmierer seit der Erfindung des Compilers immer wieder versuchen zu vermeiden. Programmiersprachen mit Garbage Collector machen das Leben einfacher, aber auf Kosten der Performance. In diesem Artikel – Den Garbage Collector eliminieren: Der RAII-WegToptal-Ingenieur Peter Goodspeed-Niklaus gibt uns einen Einblick in die Geschichte der Müllsammler und erklärt, wie Vorstellungen von Eigentum und Leihe dazu beitragen können, Müllsammler zu eliminieren, ohne ihre Sicherheitsgarantien zu gefährden.

1002580cookie-checkWas ist mit Resource Acquisition is Initialization (RAII) gemeint?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy