RAII mit Smart Pointer



  • Abend,

    habe gerade diesen Artikel: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Resource_Acquisition_Is_Initialization
    zu RAII gelesen und da wird gesagt, dass man RAII mit std::auto_ptr und boost::scoped_ptr implementieren kann. Ok, leuchtet mir ein. Aber wieso wird da nicht auch boost::shared_ptr erwähnt? Damit funktioniert doch genauso RAII? 😕



  • Kann man schon auch, aber ein shared_ptr kann eben noch einiges mehr und ist nicht direkt dafür gedacht, wohingegen auto_ptr oder scoped_ptr geeignet sind RAII direkt umzusetzen. shared_ptr hat lediglich dafür einen zu grossen Overhead (verteilte Besitzverhältnise).



  • scoped_ptr ist im Prinzip der RAII-Smart-Pointer. Er macht nichts anderes als am Ende des Scopes automatisch delete aufzurufen.

    Wie schon von drakon angetönt, ist er im Bezug auf RAII daher um einiges anschaulicher als shared_ptr , welcher nebenbei noch Reference-Counting, benutzerdefinierte Deleter, Derived-to-Base-Konvertierungen, Threadsicherheit, eine Art Pimpl für unvollständige Typen, die Unterscheidung schwacher/starker Verweise mit weak_ptr und Spezialverhalten für das eigene Objekt mit enable_shared_from_this umsetzt. (Da wird einem bewusst, wie komplex shared_ptr eigentlich ist... ;))



  • Dieser shared_ptr benutzt ja non-intrusive ref counting. Kann ich mir mal irgendwo eine Beispielimplementierung von shared_ptr anschauen? Würde gern mal sehen, wie das mit dem Ref Counter bei non-intrusive funktioniert (Will mir aber nicht den original boost Code anschauen. Der is zu komplex und optimiert. Mir gehts nur ums Prinzip)



  • Also "Modern C++ Design" von Alexandrescu hat ein Kapitel über Smart Pointer.

    Online gibts bestimmt auch gute Erklärungen, aber müsste ich auch zuerst suchen. 😉



  • Du hast neben dem Speicherbereich für das Objekt einen zweiten Speicherbereich, der ebenfalls geteilt wird und nur eine Zahl (Anzahl der Referenzen) mit Initialwert 1 enthält. Bei der Kopie eines shared_ptr s wird diese Zahl erhöht. Im Destruktor wird die Zahl erniedrigt, und falls sie 0 erreicht (letzter shared_ptr wird zerstört), wird das Objekt zerstört und freigegeben.



  • Könnte jemand vielleicht schnell ein bißchen Code einer möglichst simplen shared_ptr Implementierung schreiben? Also nur das Notwendigste (Member, Ctor, Dtor und operator= denk ich mal)



  • Du hast Glück, dass ich sowas schon mal gemacht und sogar den Thread wiedergefunden habe 🕶
    http://www.c-plusplus.net/forum/262675



  • Etwa so, denke ich:

    template<typename t>
    class shared_ptr {
    	public:
    		shared_ptr() : myObject(NULL), myCounter(NULL) {
    		}
    
    		shared_ptr( t* Object ) : myObject(Object), myCounter(new int(1)) {
    		}
    
    		shared_ptr( const shared_ptr& Other ) {
    			take( Other );
    		}
    
    		~shared_ptr() {
    			release();
    		}
    
    		shared_ptr& operator=( const shared_ptr& Other ) {
    			release();
    			take( Other );
    		}
    
    	protected:
    		void take( const shared_ptr& Other ) {
    			myObject = Other.myObject;
    			myCounter = Other.myCounter;
    			if ( myObject )
    				++*myCounter;
    		}
    
    		void release() {
    			if ( ! myObject )
    				return;
    			if ( --*myCounter == 0 ) {
    				delete myObject;
    				delete myCounter;
    			}
    			myObject = NULL;
    			myCounter = NULL;
    		}
    
    	private:
    		t* myObject;
    		int* myCounter;
    };
    


  • Vielen Dank euch beiden! 👍

    @Nexus: Fehlt bei deinem operator= nicht noch eine Dekrementierung von m_refcount? So wie ich das sehe setzt du doch nur die Member von this auf die Werte vom übergebenen rhs, aber du dekrementierst nirgends den Wert von this->m_refcount, oder?



  • RaderZweite schrieb:

    @Nexus: Fehlt bei deinem operator= nicht noch eine Dekrementierung von m_refcount?

    Nein, er macht copy&swap.

    Da hat er im dtor das decrement und im ctor das increment 😉



  • Der Code ist schon recht alt (war er schon zum Zeitpunkt des Posts), ich hab ihn nur mal geschrieben, um etwas herumzuexperimentieren und die Hintergründe besser zu verstehen. Eingesetzt wurde er nie, wirklich getestet auch nicht.

    Der Schnipsel entspricht auch nicht 1:1 dem Originalcode, ich habe dazumals einige Dinge vereinfacht (und auch kleinere Schreibfehler gemacht :)).



  • Nexus schrieb:

    scoped_ptr ist im Prinzip der RAII-Smart-Pointer. Er macht nichts anderes als am Ende des Scopes automatisch delete aufzurufen.

    Im Zusammenhang damit sollte man evtl. auch den unique_ptr erwähnen.
    unique_ptr ist im Prinzip der RAII-Smart-Pointer ab C++0x.


Anmelden zum Antworten