Ich versuche gerade zu lernen, wie man intelligente Zeiger verwendet. Bei einigen Experimenten entdeckte ich jedoch die folgende Situation, für die ich keine zufriedenstellende Lösung finden konnte:
Stellen Sie sich vor, Sie haben ein Objekt der Klasse A als Eltern eines Objekts der Klasse B (das Kind), aber beide sollten sich kennen:
class A;
class B;
class A
{
public:
void addChild(std::shared_ptr<B> child)
{
children->push_back(child);
// How to do pass the pointer correctly?
// child->setParent(this); // wrong
// ^^^^
}
private:
std::list<std::shared_ptr<B>> children;
};
class B
{
public:
setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
};
private:
std::shared_ptr<A> parent;
};
Die Frage ist, wie ein Objekt der Klasse A ein std::shared_ptr
von sich selbst ( this
) an sein Kind weitergeben kann.
Es gibt Lösungen für gemeinsam genutzte Boost-Zeiger ( Getting a boost::shared_ptr
forthis
), aber wie geht man mit den std::
intelligenten Zeigern damit um?
c++
this
shared-ptr
this-pointer
Ikarus
quelle
quelle
Antworten:
Es gibt
std::enable_shared_from_this
nur zu diesem Zweck. Sie erben davon und können.shared_from_this()
innerhalb der Klasse aufrufen . Außerdem erstellen Sie hier zirkuläre Abhängigkeiten, die zu Ressourcenlecks führen können. Das kann mit der Verwendung von gelöst werdenstd::weak_ptr
. Ihr Code könnte also so aussehen (vorausgesetzt, Kinder verlassen sich auf die Existenz eines Elternteils und nicht umgekehrt):Beachten Sie jedoch, dass für Anrufe
.shared_from_this()
erforderlichthis
ist , dass sie dem Anrufpunkt gehörenstd::shared_ptr
. Dies bedeutet, dass Sie ein solches Objekt nicht mehr auf einem Stapel erstellen können und im Allgemeinen nicht mehr.shared_from_this()
innerhalb eines Konstruktors oder Destruktors aufrufen können .quelle
shared_ptr
basierend auf einer Standardkonstruktion zu erstellenshared_ptr
und auf was auch immer Sie zeigen möchten ...shared_ptr
s sind für diese Frage irrelevant.shared_from_this
Die Voraussetzungen besagen eindeutig, dass das Objektshared_ptr
zum Zeitpunkt des Anrufs einigen gehören muss (nicht nur darauf hingewiesen wird) .shared_ptr
ist zum Zeitpunkt des Anrufs erforderlichshared_ptr<Foo> p(new Foo());
,shared_ptr
übernimmt jedoch in einem typischen Verwendungsmuster, dh so etwas wie , das Eigentum an dem Objekt erst, nachdem es vollständig erstellt wurde. Es ist möglich, dies zu umgehen, indem Sie einenshared_ptr
Konstruktor erstellen, der mit initialisiert wurde,this
und ihn an einem nicht lokalen Ort speichern (z. B. in einem Referenzargument), damit er nicht stirbt, wenn der Konstruktor abgeschlossen ist. Es ist jedoch unwahrscheinlich, dass dieses verschlungene Szenario notwendig ist.Sie haben mehrere Probleme in Ihrem Design, die auf Ihr Missverständnis von intelligenten Zeigern zurückzuführen zu sein scheinen.
Intelligente Zeiger werden verwendet, um den Besitz zu deklarieren. Sie brechen dies, indem Sie erklären, dass beide Elternteile alle Kinder besitzen, aber auch, dass jedes Kind seine Eltern besitzt. Beides kann nicht wahr sein.
Außerdem geben Sie einen schwachen Zeiger zurück
getChild()
. Auf diese Weise erklären Sie, dass sich der Anrufer nicht um das Eigentum kümmern sollte. Dies kann sehr einschränkend sein, aber Sie müssen auch sicherstellen, dass das betreffende Kind nicht zerstört wird, solange noch schwache Zeiger vorhanden sind. Wenn Sie einen intelligenten Zeiger verwenden, wird dieser von selbst aussortiert .Und das Letzte. Wenn Sie neue Entitäten akzeptieren, sollten Sie normalerweise Rohzeiger akzeptieren. Intelligente Zeiger können ihre eigene Bedeutung für den Austausch von Kindern zwischen Eltern haben. Für den allgemeinen Gebrauch sollten Sie jedoch rohe Zeiger akzeptieren.
quelle