Циклические ссылки: a shared_ptr<>
на то, что имеет shared_ptr<>
на исходный объект. Конечно, вы можете использовать weak_ptr<>
, чтобы разорвать этот цикл.
Я добавляю следующее в качестве примера того, о чем я говорю в комментариях.
class node : public enable_shared_from_this<node> {
public :
void set_parent(shared_ptr<node> parent) { parent_ = parent; }
void add_child(shared_ptr<node> child) {
children_.push_back(child);
child->set_parent(shared_from_this());
}
void frob() {
do_frob();
if (parent_) parent_->frob();
}
private :
void do_frob();
shared_ptr<node> parent_;
vector< shared_ptr<node> > children_;
};
В этом примере у вас есть дерево узлов, каждый из которых содержит указатель на своего родителя. Функция-член frob () по какой-либо причине ряби вверх по дереву. (Это не совсем странно; некоторые GUI-фреймворки работают таким образом).
Проблема в том, что если вы потеряете ссылку на самый верхний узел, то самый верхний узел все еще будет содержать сильные ссылки на своих дочерних элементов, и все его дочерние элементы также будут иметь строгую ссылку на своих родителей. Это означает, что существуют циклические ссылки, не позволяющие всем экземплярам очистить себя, в то время как на самом деле нет способа достичь дерева из кода, эта утечка памяти.
class node : public enable_shared_from_this<node> {
public :
void set_parent(shared_ptr<node> parent) { parent_ = parent; }
void add_child(shared_ptr<node> child) {
children_.push_back(child);
child->set_parent(shared_from_this());
}
void frob() {
do_frob();
shared_ptr<node> parent = parent_.lock(); // Note: parent_.lock()
if (parent) parent->frob();
}
private :
void do_frob();
weak_ptr<node> parent_; // Note: now a weak_ptr<>
vector< shared_ptr<node> > children_;
};
Здесь родительский узел был заменен слабым указателем. У него больше нет права голоса во время жизни узла, к которому он относится. Таким образом, если самый верхний узел выходит из области видимости, как в предыдущем примере, тогда, хотя он содержит строгие ссылки на своих дочерних элементов, его дочерние элементы не содержат строгих ссылок на своих родителей. Таким образом, нет сильных ссылок на объект, и он очищается. В свою очередь, это приводит к тому, что дети теряют одно сильное упоминание, которое заставляет их убирать и так далее. Короче говоря, это не утечка. И просто путем стратегической замены shared_ptr <> на weak_ptr <>.
Примечание. Вышеприведенное относится в равной степени к std :: shared_ptr <> и std :: weak_ptr <>, как и для boost :: shared_ptr <> и boost :: weak_ptr <>.