RAII



  • @manni66
    Genau darum geht es doch, dass der Destruktor immer aufgerufen wird, wenn die Variable ihren Gültigkeitsbereich verlässt.
    Sagt der hier: Wikipedia
    Aber da wird z. B. nur ein Stream geschlossen oder so. Aber oft hört man, dass man mit RAII kein delete mehr aufrufen muss. Und genau da ist meine Frage wie das gehen soll.
    @Nukularfüsiker
    Wieso Stack Overflow? Das liegt doch alles auf dem Heap 😕



  • Classx *Class1 = new Classx
    

    Classx *Class1 Class1 liegt auf den Stack ihres Gültigkeitsbereich und wird vom "System aufgeräumt", wenn der Gültigkeitsbereich verlassen wird.

    Die Instance auf der Zeiger *Class1 zeigt, wird natürlich nur mit einen delete Class1 gelöscht, welches sich auf dem Heap befindet.



  • Denksportler schrieb:

    @Nukularfüsiker
    Wieso Stack Overflow? Das liegt doch alles auf dem Heap 😕

    Was passiert denn, wenn delete auf einen Objekt-Zeiger aufgerufen wird? Der Destruktor wird aufgerufen.
    Und was passiert wohl, wenn ein Objekt per delete this in seinem Destruktor seinen eigenen Destruktor aufruft? (Hintergrundwissen: Bei einem Funktionsaufruf wird die Rücksprungadresse auf den Stack geschoben)

    RAII heißt einfach, ganz kurz gesagt, dass man im Konstruktor die Ressourcen belegt und im Destruktor wieder freigibt. Denn der Konstruktor wird aufgerufen, wenn das Objekt anfängt zu leben und der Destruktor wenn es aufhört zu leben. Beide werden automatisch aufgerufen, und das macht man sich zunutze.

    Das ist schon alles.



  • Was du suchst ist das:

    class A
    {
     int *x;
    
    public:
     A()
     {
      x = new int;
    
      *x = 100;
     }
    
     ~A()
     {
      delete x;
     }
    
     // Copy Konstruktor, etc. fehlen und sind natürlich zu implementieren!
    };
    
    void Foo()
    {
     A blub;
    } // int *x wird freigegeben
    


  • Denksportler schrieb:

    Genau darum geht es doch, dass der Destruktor immer aufgerufen wird, wenn die Variable ihren Gültigkeitsbereich verlässt.

    Das wird es auch bei Stackvariablen. RAII arbeitet ausschließlich mit solchen, und kapselt die dynamische Speicherverwaltung falls nötig.

    Beispiel (ich nehme hier absichtlich auto_ptr, weil das auf jedem C++ Compiler laufen sollte, auch wenn es bessere Lösungen gibt):

    #include <memory>
    
    class A{/*... komplexerer Inhalt ...*/};
    
    int main()
    {
        std::auto_ptr<A> a(new A());
    }   // <-- Destruktor von a wird aufgerufen
    

    Man kann damit noch andere Sachen basteln.

    z.B. Verwende ich dies für Datenbanktransaktionen: Bei der Objektinitialisierung wird die Transaktion geöffnet, beim Destruktor verworfen, nur wenn ich explizit das Commit der Klasse aufrufe, wird geschrieben. So ist sichergestellt das im Fehlerfall die Transaktion zurückgesetzt wird.

    Merke also: RAII arbeitet grundsätzlich mit Stackvariablen, diese wiederum können sich um Speicherallokation/-freigabe (wie auto_ptr, oder andere Smartpointer) kümmern, oder um gänzlich andere Ressourcen.



  • Danke für eure Erklärungen. Also muss ich wenn ich ein Klassenobjekt mit new erzeuge auch wieder mit delete löschen.
    Ich habe aber jetzt in der boost Bibliothek den scoped_ptr gefunden.
    Aber kann ich den Speicher eines scoped_ptr wieder freigeben, bevor er seinen Gültigkeitsbereich verläasst?
    In der Referenz habe ich nur den Destruktor gefunden, und kann man den ohne weiteres dann einfach aufrufen?
    Selber ausprobieren kann ich es leider noch nicht, da ich noch eine ganze Weile brauche, bis die boost lib runtergeladen ist.



  • RAII ist ein Akronym. Es steht für "Resource Acquisition Is Initialization". Die eigentliche Idee ist es, Ressourcen (zB reservierter Speicher, geöffnete Dateien, etc) an Objekte zu koppeln, so dass sie "verantwortlich" für die Verwaltung werden. Beispielsweise verwaltet/besitzt ein std::list<>-Objekt all seine Knotenobjekte. Ein ifstream-Objekt verwaltet eine geöffnete Datei. Verantwortung für Ressourcen so an Objekte zu delegieren, ist der ganze Witz an der Sache. Wenn man dieses Prinzip zu schätzen weiß und sich auch Design-technisch danach ausrichtet, geht die Gefahr von Ressourcen-Lecks durch Programmierfehler (hier ein delete vergessen, dort ein fclose vergessen) gegen Null.



  • Denksportler schrieb:

    Ich habe aber jetzt in der boost Bibliothek den scoped_ptr gefunden.
    Aber kann ich den Speicher eines scoped_ptr wieder freigeben, bevor er seinen Gültigkeitsbereich verläasst?

    "Speicher eines scoped_ptr" könnte auf ein Missverständnis hindeuten. Das scoped_ptr-Objekt liegt natürlich auch irgendwo im Speicher. Aber ich glaube das ist nicht das, was Du meintest, richtig? Du musst das schon von einander trennen und nicht in einen Topf werfen. Das scoped_ptr-Dingen und das, worauf er zeigt sind zwei verschiedene Dinge, und beides Objekte. Wenn ich mich richtig erinnere, bietet scoped_ptr eine reset-Funktion an, mit der der Speicher, auf den der scoped_ptr zeigt, früher wieder freigegeben werden kann.

    Denksportler schrieb:

    In der Referenz habe ich nur den Destruktor gefunden, und kann man den ohne weiteres dann einfach aufrufen?

    Nein. Destrukturen ruft man nur ganz ganz selten manuell auf. Destruktoren werden automatisch aufgerufen, wenn der Gültigkeitsbereich verlassen/beendet wird oder wenn man ein dynamisch erzeugtes Objekt per delete oder delete[] wieder löschen will.



  • Denksportler schrieb:

    Aber kann ich den Speicher eines scoped_ptr wieder freigeben, bevor er seinen Gültigkeitsbereich verläasst?

    #include <boost/scoped_ptr.hpp>
    
    int main()
    {
        boost::scoped_ptr<int> a(new int(1));
        a.reset(0);
    }
    


  • Ok danke, für eure Antworten. Bosst ist jett runtergeladen und dann probier ich das jetzt mal alles aus.



  • asc schrieb:

    Das wird es auch bei Stackvariablen. RAII arbeitet ausschließlich mit solchen,

    Warum sollte RAII nur mit Variablem auf dem Stack gehen? Ich kann ein file/stream auch mit new anlegen und beim delete wird immer noch automatisch close aufgerufen.



  • asc schrieb:

    Merke also: RAII arbeitet grundsätzlich mit Stackvariablen

    Nö.

    RAII ist einfach RAII und vollkommen orthogonal zu automatic storage duration vs. new/delete.



  • tschoiren schrieb:

    asc schrieb:

    Das wird es auch bei Stackvariablen. RAII arbeitet ausschließlich mit solchen,

    Warum sollte RAII nur mit Variablem auf dem Stack gehen? Ich kann ein file/stream auch mit new anlegen und beim delete wird immer noch automatisch close aufgerufen.

    Gut, mag sein, aber dann muss man deutlich mehr auf Exceptions etc. aufpassen.


Anmelden zum Antworten