Verständnis der Bedeutung des Begriffs und des Konzepts - RAII (Ressourcenerwerb ist Initialisierung)

StackOverflow https://stackoverflow.com/questions/712639

Frage

Könnten Sie C ++ - Entwickler bitte eine gute Beschreibung dessen geben, was Raii ist, warum es wichtig ist und ob es für andere Sprachen relevant sein könnte oder nicht?

ich tun weiß ein bisschen. Ich glaube, es steht für "Ressourcenerwerb ist Initialisierung". Dieser Name ist jedoch nicht mit meinem (möglicherweise falschen) Verständnis, was Raii ist: Ich habe den Eindruck, dass Raii eine Möglichkeit ist, Objekte auf dem Stapel zu initialisieren, so dass die Zerstörer automatisch, wenn diese Variablen aus dem Spielraum gehen Seien Sie so genannt, was die Ressourcen beseitigt.

Warum wird das nicht genannt "Verwenden Sie den Stapel, um die Reinigung auszulösen" (UTSTTC :)? Wie kommst du von dort zu "Raii"?

Und wie können Sie etwas auf dem Stapel machen, das die Bereinigung von etwas verursacht, das auf dem Haufen lebt? Gibt es auch Fälle, in denen Sie Raii nicht verwenden können? Wünschen Sie sich jemals eine Müllsammlung? Zumindest ein Müllsammler, den Sie für einige Objekte verwenden könnten, während sie andere verwaltet werden lassen?

Vielen Dank.

War es hilfreich?

Lösung

Warum wird das nicht genannt "Verwenden Sie den Stapel, um die Reinigung auszulösen" (UTSTTC :)?

Raii sagt Ihnen, was zu tun ist: Erwerben Sie Ihre Ressource in einem Konstruktor! Ich würde hinzufügen: eine Ressource, ein Konstruktor. UTSTTC ist nur eine Anwendung davon, Raii ist viel mehr.

Ressourcenmanagement ist scheiße. Hier ist Ressource alles, was nach dem Gebrauch gereinigt werden muss. Studien zu Projekten auf vielen Plattformen zeigen, dass die meisten Fehler mit dem Ressourcenmanagement zusammenhängen - und es ist besonders schlecht unter Windows (aufgrund der vielen Arten von Objekten und Allocatoren).

In C ++ ist das Ressourcenmanagement aufgrund der Kombination von Ausnahmen und (C ++ - Stil-) Vorlagen besonders kompliziert. Für einen Blick unter die Motorhaube siehe Gotw8).


C ++ garantiert, dass der Destruktor aufgerufen wird dann und nur dann, wenn Der Konstruktor gelang es. Wenn RAII darauf stützt, kann er viele böse Probleme lösen, die der durchschnittliche Programmierer möglicherweise nicht einmal bewusst ist. Hier sind ein paar Beispiele, die über die "meine lokalen Variablen werden wann immer ich zurückkommt" zerstört.

Beginnen wir mit einem übermäßig vereinfachten FileHandle Klasse mit Raii:

class FileHandle
{
    FILE* file;

public:

    explicit FileHandle(const char* name)
    {
        file = fopen(name);
        if (!file)
        {
            throw "MAYDAY! MAYDAY";
        }
    }

    ~FileHandle()
    {
        // The only reason we are checking the file pointer for validity
        // is because it might have been moved (see below).
        // It is NOT needed to check against a failed constructor,
        // because the destructor is NEVER executed when the constructor fails!
        if (file)
        {
            fclose(file);
        }
    }

    // The following technicalities can be skipped on the first read.
    // They are not crucial to understanding the basic idea of RAII.
    // However, if you plan to implement your own RAII classes,
    // it is absolutely essential that you read on :)



    // It does not make sense to copy a file handle,
    // hence we disallow the otherwise implicitly generated copy operations.

    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;



    // The following operations enable transfer of ownership
    // and require compiler support for rvalue references, a C++0x feature.
    // Essentially, a resource is "moved" from one object to another.

    FileHandle(FileHandle&& that)
    {
        file = that.file;
        that.file = 0;
    }

    FileHandle& operator=(FileHandle&& that)
    {
        file = that.file;
        that.file = 0;
        return *this;
    }
}

Wenn die Konstruktion ausfällt (mit Ausnahme), wird keine andere Mitgliedsfunktion - nicht einmal der Destruktor - aufgerufen.

Raii vermeidet die Verwendung von Objekten in einem ungültigen Zustand. Es erleichtert das Leben bereits, bevor wir das Objekt überhaupt verwenden.

Lassen Sie uns nun einen Blick auf temporäre Objekte werfen:

void CopyFileData(FileHandle source, FileHandle dest);

void Foo()
{
    CopyFileData(FileHandle("C:\\source"), FileHandle("C:\\dest"));
}

Es gibt drei Fehlerfälle zu behandeln: Es kann keine Datei geöffnet werden, nur eine Datei kann geöffnet werden, beide Dateien können geöffnet werden, aber das Kopieren der Dateien ist fehlgeschlagen. In einer Nicht-RAII-Implementierung, Foo Müsste alle drei Fälle explizit behandeln.

Raii veröffentlicht Ressourcen, die erworben wurden, auch wenn in einer Erklärung mehrere Ressourcen erfasst werden.

Lassen Sie uns nun einige Objekte zusammenfassen:

class Logger
{
    FileHandle original, duplex;   // this logger can write to two files at once!

public:

    Logger(const char* filename1, const char* filename2)
    : original(filename1), duplex(filename2)
    {
        if (!filewrite_duplex(original, duplex, "New Session"))
            throw "Ugh damn!";
    }
}

Der Konstruktor von Logger wird scheitern, wenn original'S -Konstruktor schlägt fehl (weil filename1 konnte nicht geöffnet werden), duplex'S -Konstruktor schlägt fehl (weil filename2 konnte nicht geöffnet werden) oder in die Dateien im Inneren schreiben LoggerDer Konstruktorkörper scheitert. In einem dieser Fälle, Logger'S Destructor wird nicht aufgerufen werden - also können wir uns nicht verlassen Logger's Destructor zur Veröffentlichung der Dateien. Doch wenn original wurde konstruiert, sein Destruktor wird während der Aufräumarbeiten der Aufräumarbeiten aufgerufen Logger Konstrukteur.

Raii vereinfacht die Reinigung nach Teilkonstruktion.


Negative Punkte:

Negative Punkte? Alle Probleme können mit Raii und intelligenten Zeigern gelöst werden ;-)

Raii ist manchmal unhandlich, wenn Sie einen verzögerten Erwerb benötigen und aggregierte Objekte auf den Haufen drücken.
Stellen Sie sich vor, der Logger braucht a SetTargetFile(const char* target). In diesem Fall muss das Griff, das noch Mitglied sein muss Logger, muss auf dem Haufen liegen (z. B. in einem intelligenten Zeiger, um die Zerstörung des Griffs angemessen auszulösen.

Ich habe mir nie wirklich die Müllsammlung gewünscht. Wenn ich C# mache, fühle ich manchmal einen Moment der Glückseligkeit, den ich mich einfach nicht darum kümmern muss, aber viel mehr vermisse ich alle coolen Spielzeuge, die durch deterministische Zerstörung erzeugt werden können. (Verwendung IDisposable Schnitt es einfach nicht.)

Ich hatte eine besonders komplexe Struktur, die möglicherweise von GC profitiert haben könnte, wo "einfache" intelligente Zeiger in mehreren Klassen kreisförmige Referenzen verursachen würden. Wir haben uns durcheinander gebracht, indem wir starke und schwache Zeiger sorgfältig ausbalancieren, aber wenn wir etwas ändern wollen, müssen wir ein großes Beziehungsdiagramm studieren. GC war vielleicht besser, aber einige der Komponenten hielten Ressourcen, die so schnell wie möglich freigegeben werden sollten.


Ein Hinweis auf dem FileHandle -Beispiel: Es war nicht abgeschlossen, nur eine Probe -, wurde jedoch falsch. Vielen Dank an Johannes Schaub für den Hinweis und Freedoverflow, dass Sie es in eine korrekte C ++ 0x -Lösung verwandelt haben. Im Laufe der Zeit habe ich mich mit dem Ansatz entschieden Hier dokumentiert.

Andere Tipps

Es gibt hervorragende Antworten da draußen, also füge ich nur einige vergessene Dinge hinzu.

0. Raii handelt von Scopes

Raii handelt von beiden:

  1. Erfassen einer Ressource (unabhängig von welcher Ressource) im Konstruktor und das Erziehen von sie im Destruktor.
  2. Wenn der Konstruktor ausgeführt wird, wenn die Variable deklariert wird, und der Destruktor automatisch ausgeführt wird, wenn die Variable aus dem Umfang ausgeht.

Andere antworteten bereits darüber, also werde ich nicht näher erläutern.

1. Wenn Sie in Java oder C#codieren, verwenden Sie bereits Raii ...

Monsieur Jourdain: Was! Wenn ich sage: "Nicole, bring mir meine Hausschuhe und gib mir meinen Nachtsack", das ist Prosa?

Philosophie Meister: Ja, Sir.

Monsieur Jourdain: Seit mehr als vierzig Jahren habe ich Prosa gesprochen, ohne etwas darüber zu wissen, und ich bin Ihnen sehr verpflichtet, dass Sie mir das beigebracht haben.

- Molière: Der Mittelklasse Gentleman, Akt 2, Szene 4

Wie Monsieur Jourdain mit Prosa, C# und sogar Java -Menschen verwenden bereits Raii, aber auf versteckte Weise. Zum Beispiel der folgende Java -Code (der in C# auf die gleiche Weise geschrieben wird, indem er ersetzt wird synchronized mit lock):

void foo()
{
   // etc.

   synchronized(someObject)
   {
      // if something throws here, the lock on someObject will
      // be unlocked
   }

   // etc.
}

... verwendet bereits RAII: Die MUTEX -Akquisition erfolgt im Schlüsselwort (synchronized oder lock), und die unauffällige Erscheinung erfolgt beim Verlassen des Umfangs.

Es ist so natürlich in seiner Notation, dass es fast keine Erklärung erfordert, selbst für Menschen, die nie von Raii gehört haben.

Der Vorteil C ++ hat über Java und C# hier ist, dass alles mit Raii gemacht werden kann. Zum Beispiel gibt es kein direktes Einbauäquivalent von synchronized Noch lock In C ++, aber wir können sie immer noch haben.

In C ++ würde es geschrieben:

void foo()
{
   // etc.

   {
      Lock lock(someObject) ; // lock is an object of type Lock whose
                              // constructor acquires a mutex on
                              // someObject and whose destructor will
                              // un-acquire it 

      // if something throws here, the lock on someObject will
      // be unlocked
   }

   // etc.
}

Dies kann leicht auf den Java/C# -Stweg geschrieben werden (unter Verwendung von C ++ - Makros):

void foo()
{
   // etc.

   LOCK(someObject)
   {
      // if something throws here, the lock on someObject will
      // be unlocked
   }

   // etc.
}

2. Raii haben alternative Verwendung

Weißer Kaninchen: [Gesang] Ich bin spät / ich bin spät / für ein sehr wichtiges Datum. / Keine Zeit zu sagen "Hallo". / Auf Wiedersehen. / Ich bin zu spät, ich bin zu spät, ich bin zu spät.

- Alice im Wunderland (Disney -Version, 1951)

Sie wissen, wann der Konstruktor aufgerufen wird (bei der Objekterklärung), und Sie wissen, wann sein entsprechender Destruktor aufgerufen wird (am Ausgang des Bereichs), sodass Sie fast magischen Code mit nur einer Zeile schreiben können. Willkommen im C ++ - Wonderland (zumindest aus Sicht eines C ++ - Entwicklers).

Sie können beispielsweise ein Gegenobjekt schreiben (ich lasse dies als Übung) und verwenden es nur, indem Sie seine Variable deklarieren, wie das obige Sperrobjekt verwendet wurde:

void foo()
{
   double timeElapsed = 0 ;

   {
      Counter counter(timeElapsed) ;
      // do something lengthy
   }
   // now, the timeElapsed variable contain the time elapsed
   // from the Counter's declaration till the scope exit
}

Was natürlich wiederum die Java/C# -Straße mit einem Makro geschrieben werden kann:

void foo()
{
   double timeElapsed = 0 ;

   COUNTER(timeElapsed)
   {
      // do something lengthy
   }
   // now, the timeElapsed variable contain the time elapsed
   // from the Counter's declaration till the scope exit
}

3. Warum fehlt C ++? finally?

Schreien] Es ist das Finale Countdown!

-Europa: Der letzte Countdown (Entschuldigung, ich hatte keine Zitate, hier ... :-)

Das finally Klausel wird in C#/java verwendet return oder eine geworfene Ausnahme).

Die Leser der klugen Spezifikation haben bemerkt, dass C ++ keine endgültige Klausel hat. Und dies ist kein Fehler, da C ++ es nicht benötigt, da Raii bereits die Entsorgung von Ressourcen verarbeitet. (Und glauben Sie mir, ein C ++ - Destruktor zu schreiben, ist Größen leichter als die richtige Java -Klausel oder sogar die korrekte Entsendung eines C#).

Trotzdem manchmal a finally Klausel wäre cool. Können wir es in C ++ machen? Ja wir können! Und wieder mit einer alternativen Verwendung von Raii.

Schlussfolgerung: Raii ist eine mehr als Philosophie in C ++: Es ist C ++

Raii? Das ist C ++ !!!

- Der empörte Kommentar des C ++ - Entwicklers, schamlos von einem obskuren Sparta -König und seinen 300 Freunden kopiert

Wenn Sie ein gewisses Maß an Erfahrungen in C ++ erreichen, denken Sie an, in Bezug auf zu denken Raii, bezüglich Einschränkungen und Zerstörer automatisierte Ausführung.

Sie beginnen in Bezug auf zu denken Bereiche, und die { und } Charaktere werden zu den wichtigsten in Ihrem Code.

Und fast alles passt in Bezug auf Raii: Ausnahmesicherheit, Mutexes, Datenbankverbindungen, Datenbankanforderungen, Serververbindung, Uhren, Betriebssystemgriffe usw. und zuletzt, aber nicht zuletzt.

Der Datenbankteil ist nicht vernachlässigbar, da Sie, wenn Sie den Preis akzeptieren, sogar in eine "schreiben können" schreiben können.Transaktionsprogrammierung"Stil, Ausführung von Zeilen und Codezeilen bis zum Ende, wenn Sie alle Änderungen begehen oder, wenn nicht möglich, alle Änderungen zurückgezogen haben (solange jede Zeile zumindest die starke Ausnahmegarantie erfüllt ) (siehe den zweiten Teil davon Herbs Sutter -Artikel für die Transaktionsprogrammierung).

Und wie ein Puzzle passt alles.

Raii ist so viel Teil von C ++, C ++ könnte ohne es nicht C ++ sein.

Dies erklärt, warum erfahrene C ++ - Entwickler in Raii so verliebt sind und warum Raii das erste ist, was sie beim Versuch einer anderen Sprache suchen.

Und es erklärt, warum der Garbage Collector, während ein großartiges Stück Technologie an sich selbst nicht so beeindruckend ist, aus Sicht eines C ++ - Entwicklers:

  • Raii behandelt bereits die meisten Fälle, die von einem GC behandelt wurden
  • Ein GC handelt besser als Raii mit kreisförmigen Referenzen auf reine verwaltete Objekte (gemildert durch intelligente Verwendungen schwacher Zeiger)
  • Noch ein GC ist auf Speicher beschränkt, während Raii jede Art von Ressourcen bewältigen kann.
  • Wie oben beschrieben, kann Raii viel, viel mehr tun ...

Raii verwendet C ++ Destructors -Semantik, um Ressourcen zu verwalten. Betrachten Sie zum Beispiel einen intelligenten Zeiger. Sie haben einen parametrisierten Konstruktor des Zeigers, der diesen Zeiger mit dem Objektadress initialisiert. Sie weisen einen Zeiger auf Stack zu:

SmartPointer pointer( new ObjectClass() );

Wenn der intelligente Zeiger aus dem Geltungsbereich ausgeht, löscht der Destruktor der Zeigerklasse das angeschlossene Objekt. Der Zeiger ist stapelalloziert und das Objekt-heap-zugeteilt.

Es gibt bestimmte Fälle, in denen Raii nicht hilft. Wenn Sie beispielsweise intelligente Smart-Zeiger (wie Boost :: Shared_ptr) Referenzausschnitt verwenden und eine graphische Struktur mit einem Zyklus erstellen, riskieren Sie, dass Sie ein Speicherleck gegenüberstehen, da sich die Objekte in einem Zyklus gegenseitig verhindern, dass sie freigegeben werden. Die Müllsammlung würde dagegen helfen.

Ich stimme der CPitis zu. Ich möchte aber hinzufügen, dass die Ressourcen nicht nur Speicher sein können. Die Ressource kann eine Datei, ein kritischer Abschnitt, ein Thread oder eine Datenbankverbindung sein.

Es wird als Ressourcenerwerb als Initialisierung bezeichnet, da die Ressource erfasst wird, wenn das Objekt, das die Ressource steuert, konstruiert wird, wenn der Konstruktor fehlgeschlagen ist (dh aufgrund einer Ausnahme), wird die Ressource nicht erfasst. Sobald das Objekt aus dem Umfang ausgeht, wird die Ressource veröffentlicht. C ++ garantiert, dass alle Objekte auf dem Stapel, die erfolgreich konstruiert wurden, zerstört werden (dies schließt Konstruktoren von Basisklassen und Mitgliedern ein, auch wenn der Superklassenkonstruktor fehlschlägt).

Die Rationale hinter RAII ist es, die Ausnahme der Ressourcenerwerb zu sichern. Dass alle erworbenen Ressourcen ordnungsgemäß freigegeben werden, unabhängig davon, wo eine Ausnahme eintritt. Dies beruht jedoch auf die Qualität der Klasse, die die Ressource erwirbt (dies muss ausnahmslos sicher sein und dies ist schwierig).

Ich würde es gerne etwas stärker ausdrücken als frühere Antworten.

Raii, Ressourcenerwerb ist die Initialisierung bedeutet, dass alle erworbenen Ressourcen im Kontext der Initialisierung eines Objekts erfasst werden sollten. Dies verbietet den "nackten" Ressourcenerwerb. Die Begründung ist, dass die Reinigung in C ++ auf Objektbasis und nicht auf Funktionsbasis funktioniert. Daher sollte die gesamte Reinigung durch Objekte und keine Funktionsaufrufe durchgeführt werden. In diesem Sinne ist C ++ eher objektorientiert als z. B. Java. Die Java -Reinigung basiert auf Funktionsaufrufen in finally Klauseln.

Das Problem bei der Müllsammlung ist, dass Sie die deterministische Zerstörung verlieren, die für Raii von entscheidender Bedeutung ist. Sobald eine Variable aus dem Umfang ausgeht, liegt es an dem Müllsammler, wenn das Objekt zurückerobert wird. Die Ressource, die vom Objekt gehalten wird, wird weiterhin gehalten, bis der Destruktor angerufen wird.

Raii stammt aus der Ressourcenzuweisung ist die Initialisierung. Grundsätzlich bedeutet dies, dass das konstruierte Objekt, wenn ein Konstruktor die Ausführung beendet, vollständig initialisiert und verwendet wird. Dies impliziert auch, dass der Destruktor alle Ressourcen (z. B. Speicher, OS -Ressourcen) des Objekts freigibt.

Im Vergleich zu müll gesammelten Sprachen/Technologien (z. B. Java, .NET) ermöglicht C ++ eine vollständige Kontrolle über die Lebensdauer eines Objekts. Bei einem von Stack zugewiesenen Objekt werden Sie wissen, wann der Destruktor des Objekts aufgerufen wird (wenn die Ausführung aus dem Geltungsbereich ausgeht), was bei der Müllsammlung nicht wirklich kontrolliert wird. Selbst wenn Sie intelligente Zeiger in C ++ (z. B. Boost :: Shared_Ptr) verwenden, wissen Sie, dass der Zerstörer dieses Objekts, wenn es keinen Bezug auf das spitzen Objekt gibt, aufgerufen wird.

Und wie können Sie etwas auf dem Stapel machen, das die Bereinigung von etwas verursacht, das auf dem Haufen lebt?

class int_buffer
{
   size_t m_size;
   int *  m_buf;

   public:
   int_buffer( size_t size )
     : m_size( size ), m_buf( 0 )
   {
       if( m_size > 0 )
           m_buf = new int[m_size]; // will throw on failure by default
   }
   ~int_buffer()
   {
       delete[] m_buf;
   }
   /* ...rest of class implementation...*/

};


void foo() 
{
    int_buffer ib(20); // creates a buffer of 20 bytes
    std::cout << ib.size() << std::endl;
} // here the destructor is called automatically even if an exception is thrown and the memory ib held is freed.

Wenn eine Instanz von int_buffer entsteht, muss sie eine Größe haben und die erforderliche Erinnerung zugewiesen. Wenn es aus dem Zielfernrohr geht, wird es Destructor genannt. Dies ist sehr nützlich für Dinge wie Synchronisationsobjekte. In Betracht ziehen

class mutex
{
   // ...
   take();
   release();

   class mutex::sentry
   {
      mutex & mm;
      public:
      sentry( mutex & m ) : mm(m) 
      {
          mm.take();
      }
      ~sentry()
      {
          mm.release();
      }
   }; // mutex::sentry;
};
mutex m;

int getSomeValue()
{
    mutex::sentry ms( m ); // blocks here until the mutex is taken
    return 0;  
} // the mutex is released in the destructor call here.

Gibt es auch Fälle, in denen Sie Raii nicht verwenden können?

Nein nicht wirklich.

Wünschen Sie sich jemals eine Müllsammlung? Zumindest ein Müllsammler, den Sie für einige Objekte verwenden könnten, während sie andere verwaltet werden lassen?

Niemals. Die Müllsammlung löst nur eine sehr kleine Untergruppe dynamischer Ressourcenverwaltung.

Hier gibt es bereits viele gute Antworten, aber ich würde nur hinzufügen:
Eine einfache Erklärung von RAII ist, dass in C ++ ein auf dem Stapel zugewiesener Objekt immer dann zerstört wird, wenn es aus dem Umfang ausgeht. Das heißt, ein Objekt -Destruktor wird aufgerufen und kann alle notwendigen Aufräumarbeiten durchführen.
Das heißt, wenn ein Objekt ohne "neu" erstellt wird, ist kein "Löschen" erforderlich. Und dies ist auch die Idee hinter "intelligenten Zeigern" - sie wohnen auf dem Stapel und wickeln im Wesentlichen ein haufensbasiertes Objekt.

Raii ist eine Abkürzung für die Ressourcenerfassung ist die Initialisierung.

Diese Technik ist aufgrund ihrer Unterstützung sowohl für Konstruktoren als auch für Destruktoren und fast automatisch die Konstrukteure, die übereinstimmen, dass Argumente übergeben werden, oder im schlimmsten Fall, den der Standardkonstruktor genannt wird, wenn Explication bereitgestellt wird, ansonsten als der Standard als die Standardeinstellung bezeichnet wird, fast automatisch. Dies wird vom C ++ - Compiler hinzugefügt, wenn Sie keinen Destruktor für eine C ++ - Klasse explizit geschrieben haben. Dies geschieht nur für C ++ - Objekte, die automatisch verwaltet werden - was bedeutet, dass sie den kostenlosen Speicher nicht verwenden (Speicher zugewiesen/mit neuen, neuen []/löschen, löschen [] C ++ - Operatoren).

Die Raii-Technik nutzt diese automatisch verwaltete Objektfunktion, um die Objekte zu verarbeiten, die auf dem Heap/Freigeschäft erstellt werden, indem sie explizit nach mehr Speicher mit neu/neuer [] erstellt werden. . Die Klasse des automatisch verwalteten Objekts wickelt dieses andere Objekt ein, das im Heap/Free-Store-Speicher erstellt wird. Wenn der Konstruktor des automatisch verwalteten Objekts ausgeführt wird, wird das verpackte Objekt im Heap/Free-Store-Speicher erstellt und wenn das Griff des automatischen verwalteten Objekts den Geltungsbereich ausgeht, wird Destructor dieses automatisch verwalteten Objekts automatisch aufgerufen, in dem das verpackte Wickel aufgerufen wird Das Objekt wird mit Löschen zerstört. Wenn Sie mit OOP -Konzepten solche Objekte in eine andere Klasse in privatem Umfang einwickeln, hätten Sie keinen Zugriff auf die Mitglieder und Methoden für verpackte Klassen und dies ist der Grund, warum Smart -Zeiger (auch bekannt als Klassen) für die Klassen ausgelegt sind. Diese intelligenten Zeiger setzen das verpackte Objekt als typisiertes Objekt der externen Welt und dort aus, indem sie alle Mitglieder/Methoden aufrufen, aus denen das exponierte Speicherobjekt besteht. Beachten Sie, dass intelligente Zeiger verschiedene Geschmacksrichtungen haben, die auf unterschiedlichen Anforderungen basieren. Sie sollten sich auf die moderne C ++ -Programmierung von Andrei Alexandrescu oder die Implementierung/Dokumentation/Dokumentation der Bibliothek (www.boostorg) beziehen, um mehr darüber zu erfahren. Ich hoffe, das hilft Ihnen, Raii zu verstehen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top