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.
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