2014-03-04 3 views
6

Die Bibliothek boost smart_ptr enthält zwei Varianten, die es einer Klasse ermöglichen, shared_ptrs für sich selbst bereitzustellen, enable_shared_from_this (auch für die Smartpointer von stl verfügbar) und enable_shared_from_raw. Letzteres scheint mir überlegen zu sein, da es erlaubt, geteilte Zeiger im Konstruktor zu erzeugen. Allerdings wird diese Klasse in der Dokumentation überhaupt nicht erwähnt, nicht Teil der Root-Boost/Header, und Googling gibt meist Treffer in der tatsächlichen .hpp-Datei.Warum ist boost :: enable_shared_from_raw so undokumentiert?

Ist boost :: enable_shared_from_raw veraltet oder auf andere Weise unbrauchbar? Fehle ich etwas?

Antwort

8

Das Problem mit enable_shared_from_raw ist, dass es gefährlich ist; Sie können versehentlich Objekte verlassen.

Wenn Sie shared_from_raw aufrufen, ohne auf eine Instanz shared_ptr Besitz des Rohzeiger zu gewähren, dann ist die enable_shared_from_raw Basisklasse wird eine starke Referenz auf sich selbst halten bis Sie das tun.

Solange es einen starken Verweis auf sich selbst enthält, kann der Referenzzähler 0 nicht erreichen, bis das Objekt manuell gelöscht wird, was alle Vorteile der Verwendung eines shared_ptr vollständig beseitigt. Sobald etwas den Besitzer des rohen Zeigers übernimmt, wird der Verweis auf eine schwache Referenz reduziert und alles ist in Ordnung.

class object : boost::enable_shared_from_raw { } 

// Leak! When shared_from_raw is called, raw takes ownership of itself. 
object* raw = new object; 
boost::shared_ptr<object> bar = boost::shared_from_raw(raw); 

// This is fine; bar already owns the object when shared_from_raw is invoked. 
object* raw = new object; 
boost::shared_ptr<object> bar(raw); 
boost::shared_ptr<object> foo = boost::shared_from_raw(raw); 

// Also fine; ownership is transferred to bar. 
object* raw = new object; 
boost::shared_ptr<object> foo = boost::shared_from_raw(raw); 
boost::shared_ptr<object> bar(raw); 

// Still a leak! Nothing external has taken ownership of the raw pointer. 
object* raw = new object; 
boost::shared_ptr<object> bar = boost::shared_from_raw(raw); 
boost::shared_ptr<object> foo = bar; 

Ich denke, der häufigste Fall, wo Sie wollen würden shared_from_this() in einem Konstruktor aufzurufen ist, wenn Sie das Objekt mit irgendeiner Art von Managern registriert werden sollen; was höchstwahrscheinlich zu dem hier beschriebenen Leck führen würde.

// This use case results in a leak. 
// Nothing external takes ownership of the raw pointer. 
struct Object; 
struct ObjectManager 
{ 
    void RegisterObject(boost::shared_ptr<Object> obj) 
    { 
     m_objects.push_back(obj); 
    } 
    std::list<boost::shared_ptr<Object> > m_objects; 
}; 
static ObjectManager gObjectManager; 

struct Object : boost::enable_shared_from_raw 
{ 
    Object() 
    { 
     gObjectManager.RegisterObject(boost::shared_from_raw(this)); 
    } 
} 

enable_shared_from_this platziert zusätzliche Einschränkungen, um diese Art von Leck zu verhindern.

+0

Während es nicht wirklich erklärt, warum es so undokumentiert ist (was schwer zu erklären ist :)), werde ich das akzeptieren, da es die Einschränkungen gut beschreibt. – Dentoid