shared_ptr и циклические ссылки

Я пытался с циклическими ссылками для boost::shared_ptrи разработал следующий образец:

class A{ // Trivial class
public:
i32 i;
A(){}
A(i32 a):i(a){}
~A(){
cout<<"~A : "<<i<<endl;
}
};

shared_ptr<A> changeI(shared_ptr<A> s){
s->i++;
cout<<s.use_count()<<'\n';

return s;
}

int main() {

shared_ptr<A> p1 = make_shared<A>(3);
shared_ptr<A> p2 = p1;
shared_ptr<A> p3 = p2;
shared_ptr<A> p4 = p3;

p1 = p4; // 1) 1st cyclic ref.
cout<<p1.use_count()<<'\n';

p1 = changeI(p4); // 2) 2nd cyclic ref.

cout<<p1.use_count()<<'\n';

//  putchar('\n');
cout<<endl;
}

какие выводы

4
5
4

~A : 4

Это то, что я неверно истолковал циклические ссылки, упомянутые для boost::shared_ptr? Потому что я ожидал другого выхода, думая о косвенных ссылках на p1 после комментариев 1) а также 2),
Так что этот код не требует boost::weak_ptr! Так, каковы циклические ссылки, где weak_ptrs потребуется?

Заранее спасибо.

9

Решение

Да, вы неправильно это поняли. В вашем примере все указатели указывают на один и тот же объект, не образуя никаких циклов.

Присвоение p4 p2 является недопустимым, так как эти указатели уже были равны с самого начала.

Вот пример с реальными циклическими ссылками, может быть, это прояснит ситуацию:

struct A
{
std::shared_ptr<A> ptr;
};

void main()
{
std::shared_ptr<A> x=std::make_shared<A>();
std::shared_ptr<A> y=std::make_shared<A>();

x->ptr = y; // not quite a cycle yet
y->ptr = x; // now we got a cycle x keeps y alive and y keeps x alive
}

Вы даже можете сделать это еще проще:

void main()
{
std::shared_ptr<A> x=std::make_shared<A>();

x->ptr = x; // never die! x keeps itself alive
}

В обоих примерах объекты в shared_ptrs никогда не уничтожаются, даже после выхода из main.

22

Другие решения

Просто хотел бы указать: причина, по которой вторая строка вывода 5 и не 4 не из-за s->i++ увеличиваться, но потому что shared_ptr<A> s параметр передается по значению.

По вызову

p1 = changeI(p4); // 2) 2nd cyclic ref.

p4 будет скопирован в еще один shared_pointerвременно увеличивая use_count по одному во время действия функции.

Может быть, я играю здесь, очевидно, в капитана (;

0