Frage

ich über enable_shared_from_this lief, während die Beispiele Boost.Asio Lesen und nach dem Lesen der Dokumentation ich noch bin verloren, wie diese richtig verwendet werden soll. Kann mir jemand bitte ein Beispiel und / oder und Erklärung geben, wenn die Verwendung dieser Klasse sinnvoll ist.

War es hilfreich?

Lösung

Es ermöglicht Ihnen eine gültige shared_ptr Instanz zu erhalten, um zu this, wenn alles, was Sie haben, ist this. Ohne sie würde haben Sie keine Möglichkeit eine shared_ptr zu this zu bekommen, wenn Sie bereits ein als Mitglied hatte. Dieses Beispiel aus der Boost-Dokumentation für enable_shared_from_this :

class Y: public 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
}

Die Methode f () gibt einen gültigen shared_ptr, auch wenn es kein Mitglied Instanz hatte. Beachten Sie, dass Sie nicht einfach dies tun:

class Y: public enable_shared_from_this<Y>
{
public:

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

Der gemeinsame Zeiger, der diese aus dem „richtigen“ einem zurückgegeben werden ein anderen Referenzzähler haben, und einer von ihnen wird am Ende verlieren und hielt eine baumelnde Referenz, wenn das Objekt gelöscht wird.

enable_shared_from_this hat einen Teil von C ++ 11 Standard. Sie können es auch als gut ab Schub von dort aus.

Andere Tipps

von Dr. Dobbs Artikel über schwache Zeiger, ich denke, das Beispiel leichter zu verstehen ist (Quelle: http: // drdobbs .com / CPP / 184402026 ):

... Code wie dies wird nicht korrekt funktionieren:

int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);

Keine der beiden shared_ptr Objekte kennt den anderen, so werden beide versuchen, die Ressource freizugeben, wenn sie zerstört werden. Das führt in der Regel zu Problemen.

Und falls eine Elementfunktion ein shared_ptr Objekt benötigt, das das Objekt besitzt, dass es auf genannt wird, kann es nicht nur ein Objekt on the fly erstellen:

struct S
{
  shared_ptr<S> dangerous()
  {
     return shared_ptr<S>(this);   // don't do this!
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->dangerous();
   return 0;
}

Dieser Code hat das gleiche Problem wie das frühere Beispiel, obwohl in einer subtileren Form. Wenn es aufgebaut ist, besitzt das shared_ptr Objekt sp1 die neu zugewiesenen Ressource. Der Code innerhalb der Memberfunktion S::dangerous weiß nicht, über dieses shared_ptr Objekt, so das shared_ptr Objekt, das es von sp1 verschieden zurückgibt. Kopieren des neuen shared_ptr Objekt sp2 hilft nicht; wenn sp2 den Gültigkeitsbereich verlässt, wird die Ressource freigeben, und wenn sp1 den Gültigkeitsbereich verlässt, wird es wieder die Ressource freigeben.

Die Art und Weise, dieses Problem zu vermeiden, ist die Klassenvorlage enable_shared_from_this zu verwenden. Die Schablone nimmt ein Vorlagenart Argument, das der Name der Klasse ist, die die verwaltete Ressource definiert. Diese Klasse muss wiederum abgeleitet aus der Vorlage öffentlich sein; wie folgt aus:

struct S : enable_shared_from_this<S>
{
  shared_ptr<S> not_dangerous()
  {
    return shared_from_this();
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->not_dangerous();
   return 0;
}

Wenn Sie dies tun, denken Sie daran, dass das Objekt, auf das Sie shared_from_this nennen muss von einem shared_ptr Objekt gehört. Das wird nicht funktionieren:

int main()
{
   S *p = new S;
   shared_ptr<S> sp2 = p->not_dangerous();     // don't do this
}

Hier ist meine Erklärung, aus Schrauben und Muttern Perspektive (oben Antwort mit mir nicht ‚Klick‘). * Anmerkung, dass dies das Ergebnis einer Untersuchung der Quelle für shared_ptr und enable_shared_from_this, die mit Visual Studio kommt 2012. Vielleicht anderen Compilern enable_shared_from_this anders implementieren ... *

enable_shared_from_this<T> fügt eine private weak_ptr<T> Instanz T, die das hält ' einen wahren Referenzzähler ' für die Instanz von T.

Wenn Sie also zunächst eine shared_ptr<T> auf einen neuen T * schaffen, dass T * 's internen weak_ptr mit einem refcount von 1. Der neue shared_ptr sichert auf diesem weak_ptr grundsätzlich initialisiert wird.

T kann dann in seine Methoden, shared_from_this rufen eine Instanz von shared_ptr<T> zu erhalten, der zieht sich auf dem gleichen intern gespeicherten Referenzzähler . Auf diese Weise haben Sie immer einen Ort, an den T* Ref-count gespeichert wird, anstatt mehr shared_ptr Instanzen haben, die umeinander nicht kennen, und jeder denkt, dass sie die shared_ptr sind, die verantwortlich für ref Zählung T ist und es zu löschen, wenn ihre Referenzzählung Null erreicht.

Beachten Sie, dass mit einem boost :: intrusive_ptr nicht unter diesem Problem leidet. Dies ist oft ein bequemer Weg, um dieses Problem zu erhalten.

Es ist genau das gleiche in C ++ 11 und später. Es ist die Fähigkeit zu ermöglichen this als freigegebene Zeiger zurück, da this Ihnen einen rohen Zeiger gibt

in anderen Worten, es können Sie Code wie diesen drehen

class Node {
public:
    Node* getParent const() {
        if (m_parent) {
            return m_parent;
        } else {
            return this;
        }
    }

private:

    Node * m_parent = nullptr;
};           

in diesen:

class Node : std::enable_shared_from_this<Node> {
public:
    std::shared_ptr<Node> getParent const() {
        std::shared_ptr<Node> parent = m_parent.lock();
        if (parent) {
            return parent;
        } else {
            return shared_from_this();
        }
    }

private:

    std::weak_ptr<Node> m_parent;
};           

Eine andere Möglichkeit ist es, ein weak_ptr<Y> m_stub Mitglied in die class Y hinzuzufügen. Dann schreiben Sie:

shared_ptr<Y> Y::f()
{
    return m_stub.lock();
}

Nützlich, wenn Sie nicht die Klasse ändern Sie die sich aus (zum Beispiel anderer Leute Bibliothek erstreckt). Vergessen Sie nicht, um das Element zu initialisieren, z.B. von m_stub = shared_ptr<Y>(this) ist seine Gültigkeit, auch bei einem Konstruktor.

Es ist OK, wenn es mehr Stubs wie dieser in Vererbungshierarchie ist, wird es nicht die Zerstörung des Objekts verhindern.

Edit: Wie bereits richtig durch Benutzer nobar aus, würde der Code Y-Objekt zerstören, wenn die Zuordnung abgeschlossen ist und temporäre Variablen werden zerstört. Daher meine Antwort ist falsch.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top