Obecnie próbuję nauczyć się korzystać z inteligentnych wskaźników. Jednak podczas niektórych eksperymentów odkryłem następującą sytuację, dla której nie mogłem znaleźć satysfakcjonującego rozwiązania:
Wyobraź sobie, że masz obiekt klasy A będący rodzicem obiektu klasy B (dziecko), ale oboje powinni się znać:
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;
};
Powstaje pytanie, w jaki sposób obiekt klasy A może przekazać std::shared_ptr
siebie ( this
) swojemu dziecku?
Istnieją rozwiązania dotyczące wspólnych wskaźników Boost ( Getting a boost::shared_ptr
forthis
), ale jak sobie z tym poradzić za pomocą std::
inteligentnych wskaźników?
c++
this
shared-ptr
this-pointer
Ikar
źródło
źródło
Odpowiedzi:
Jest
std::enable_shared_from_this
tylko w tym celu. Dziedziczysz to i możesz dzwonić.shared_from_this()
z poziomu klasy. Ponadto tworzysz w tym miejscu zależności cykliczne, które mogą prowadzić do wycieków zasobów. Można to rozwiązać za pomocąstd::weak_ptr
. Twój kod może więc wyglądać tak (zakładając, że dzieci polegają na istnieniu rodzica, a nie na odwrót):Należy jednak pamiętać, że powołanie
.shared_from_this()
wymaga,this
jest własnościąstd::shared_ptr
w momencie wywołania. Oznacza to, że nie możesz już tworzyć takiego obiektu na stosie i generalnie nie możesz wywoływać.shared_from_this()
z poziomu konstruktora lub destruktora.źródło
shared_ptr
opartą na domyślnej konstrukcjishared_ptr
i czymkolwiek chcesz go wskazać ...shared_ptr
są nieistotne dla tego pytania.shared_from_this
Warunki wstępne jasno określają, że obiekt musi być własnością (a nie tylko wskazywać) przez niektórychshared_ptr
w momencie wywołania.shared_ptr
jest wymagane w momencie wywołania, ale w typowym schemacie użytkowania, czyli czymś podobnymshared_ptr<Foo> p(new Foo());
,shared_ptr
zakłada się własność obiektu dopiero po jego pełnej budowie. Można to obejść, tworzącshared_ptr
w konstruktorze zainicjowanym przezthis
i przechowując go gdzieś nielokalnie (np. W argumencie referencyjnym), aby nie umarł po zakończeniu konstruktora. Ale ten skomplikowany scenariusz raczej nie będzie potrzebny.Masz kilka problemów w swoim projektowaniu, które wydają się wynikać z niezrozumienia inteligentnych wskazówek.
Do deklarowania własności używane są inteligentne wskaźniki. Łamiesz to oświadczając, że oboje rodzice są właścicielami wszystkich dzieci, ale także, że każde dziecko posiada swojego rodzica. Obie nie mogą być prawdą.
Ponadto zwracasz słaby wskaźnik w
getChild()
. W ten sposób deklarujesz, że dzwoniący nie powinien przejmować się własnością. Teraz może to być bardzo ograniczające, ale robiąc to, musisz upewnić się, że dane dziecko nie zostanie zniszczone, gdy nadal trzymane są słabe wskaźniki, jeśli użyjesz inteligentnego wskaźnika, zostanie ono rozwiązane samo .I ostatnia sprawa. Zwykle, gdy akceptujesz nowe jednostki, powinieneś zwykle akceptować surowe wskaźniki. Inteligentny wskaźnik może mieć własne znaczenie przy zamianie dzieci między rodzicami, ale do ogólnego użytku należy akceptować surowe wskaźniki.
źródło