2008-09-26 15 views
76

Ich mache umfangreiche Verwendung von boost:shared_ptr in meinem Code. Tatsächlich werden die meisten Objekte, die auf dem Heap reserviert sind, von einem shared_ptr gehalten. Leider bedeutet das, dass ich this nicht in eine beliebige Funktion überführen kann, die eine shared_ptr übernimmt. Betrachten Sie diesen Code:Erhalten Sie einen boost :: shared_ptr für diese

void bar(boost::shared_ptr<Foo> pFoo) 
{ 
    ... 
} 

void Foo::someFunction() 
{ 
    bar(this); 
} 

Es gibt zwei Probleme hier. Zuerst wird das nicht kompiliert, da der T * -Konstruktor für shared_ptr explizit ist. Zweitens, wenn ich es erzwinge, mit bar(boost::shared_ptr<Foo>(this)) zu bauen, habe ich einen zweiten gemeinsamen Zeiger auf mein Objekt erstellt, der schließlich zu einem doppelten Löschen führen wird.

Das bringt mich zu meiner Frage: Gibt es ein Standardmuster zum Abrufen einer Kopie des vorhandenen freigegebenen Zeigers, von dem Sie wissen, dass er in einer Methode auf einem dieser Objekte existiert? Ist das Verwenden von intrusivem Referenzzählen meine einzige Option?

+0

„_Ist mit aufdringlicher Referenz hier meine einzige Option Zählen _ "Was ist los mit dieser Option? – curiousguy

+0

Vielleicht nichts. Hängt von Ihren Umständen ab. Es macht Ihre Objekte größer und funktioniert möglicherweise nicht an Orten, an denen Sie keine Kontrolle über die Klassen haben, an die Sie die Smartpointer halten. –

+0

enabe_shared_from_this ist jetzt in 'std ::'. Schau dir meine Antwort an. –

Antwort

102

Sie können aus enable_shared_from_this ableiten und dann können Sie „shared_from_this()“ statt „der“, um laichen einen gemeinsamen Zeiger auf Ihr eigenes Selbst-Objekt verwenden.

Beispiel in der Verbindung:

#include <boost/enable_shared_from_this.hpp> 

class Y: public boost::enable_shared_from_this<Y> 
{ 
public: 

    shared_ptr<Y> f() 
    { 
     return shared_from_this(); 
    } 
} 

int main() 
{ 
    shared_ptr<Y> p(new Y); 
    shared_ptr<Y> q = p->f(); 
    assert(p == q); 
    assert(!(p < q || q < p)); // p and q must share ownership 
} 

Es ist eine gute Idee, wenn Laichen Threads von einer Memberfunktion boost :: Bindung an einen shared_from_this() statt dieser. Dadurch wird sichergestellt, dass das Objekt nicht freigegeben wird.

+0

f() ist wie ".Copy()" und es ist auch eine flache Kopie. –

9

Machst du wirklich mehr geteilte Kopien von pFoo in der Bar? Wenn Sie nicht etwas verrückt nach innen zu tun sind, gerade dies tun:


void bar(Foo &foo) 
{ 
    // ... 
} 
3

Die Funktion gibt einen Zeiger zu akzeptieren will eine von zwei Verhaltensweisen tun:

  • arbeiten das Objekt wird in vergangen, und lösche es, wenn es den Gültigkeitsbereich verlässt. In diesem Fall können Sie einfach X * akzeptieren und sofort ein scoped_ptr um dieses Objekt (im Funktionskörper) legen. Dies wird funktionieren, um "dieses" oder im Allgemeinen jedes dem Heap zugewiesene Objekt zu akzeptieren.
  • Teilen ein Zeiger (es nicht besitzen) auf das jeweilige Objekt geführt wird. In diesem Fall, dass Sie tun nicht wollen überhaupt eine scoped_ptr verwenden, da Sie bei der das Objekt nicht löschen möchten Ende Ihrer Funktion. In diesem Fall ist das, was Sie theoretisch wollen, ein shared_ptr (ich habe es an anderer Stelle als linked_ptr bezeichnet). Die Boost-Bibliothek hat a version of shared_ptr, und dies wird auch in Scott Meyers 'Effective C++ Buch empfohlen (Punkt 18 in der 3. Ausgabe).

Edit: Oops ich die Frage etwas falsch verstanden, und ich sehe nun diese Antwort nicht genau die Frage Adressierung. Ich werde es trotzdem weglassen, falls das für jemanden, der an ähnlichem Code arbeitet, hilfreich sein könnte.

19

Verwenden Sie einfach einen RAW-Zeiger für Ihren Funktionsparameter anstelle von shared_ptr. Der Zweck eines Smart-Zeigers ist es, die Lebensdauer des Objekts zu steuern, aber die Lebensdauer des Objekts ist bereits durch die C++ - Scoping-Regeln garantiert: Sie existiert mindestens so lange wie das Ende Ihrer Funktion.Das heißt, der aufrufende Code kann das Objekt möglicherweise nicht löschen, bevor Ihre Funktion zurückkehrt. somit ist die Sicherheit eines "dummen" Zeigers gewährleistet, solange Sie nicht versuchen, das Objekt in Ihrer Funktion zu löschen.

Die einzige Zeit, die Sie benötigen, um ein shared_ptr in eine Funktion zu übergeben, ist, wenn Sie das Objekt an die Funktion übergeben möchten oder die Funktion eine Kopie des Zeigers erstellen soll.

+1

Einverstanden. Oft können Sie foo verwenden (const Object * object_ptr) {} foo (obj.get()); wo obj ist ein boost :: shared_ptr < Object >. Suchen Sie im Web nach Herb Sutter, ist ein anderer und Artikel Schriftsteller, der einige großartige Informationen über diese und ähnliche Probleme hat. –

+1

Es ist wenig neben dem Punkt, aber ... Wenn Sie Zeiger verwenden können, dann (am wahrscheinlichsten) können Sie Referenz verwenden, die IMO besser ist. –

+1

@ denis-bu, außer wenn ein 'NULL'-Zeiger möglich ist. Aber du machst einen guten Punkt. –

5

Mit C++ 11 shared_ptr und enable_shared_from_this ist jetzt in der Standardbibliothek. Letzteres ist, wie der Name schon sagt, für diesen Fall genau.

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

Beispiel basiert auf, dass in den Links oben:

struct Good: std::enable_shared_from_this<Good>{ 
    std::shared_ptr<Good> getptr() { 
     return shared_from_this(); 
    } 
}; 

Verwendung:

std::shared_ptr<Good> gp1(new Good); 
std::shared_ptr<Good> gp2 = gp1->getptr(); 
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n'; 
Verwandte Themen