Использование weak_ptr с циклическими ссылками

Поэтому мне довольно трудно понять, почему мы должны использовать weak_ptr, особенно с проблемами циклических ссылок, рассмотрим этот код:

class B; //forward declaration

class A {
    shared_ptr<B> b_ptr;
public:
    void set_B(shared_ptr<B>& b)
    {
        b_ptr = b;
    }
    A() { cout << "A constructor" << endl; }
    ~A() { cout << "A destructor" << endl; }
};

class B {
    shared_ptr<A> a_ptr;
public:
    void set_A(shared_ptr<A>& a)
    {
        a_ptr = a;
    }
    B() { cout << "B constructor" << endl; }
    ~B() { cout << "B destructor" << endl; }
};

int main() {
   shared_ptr<A> a = make_shared<A>();
    shared_ptr<B> b = make_shared<B>();
    a->set_B(b);
    b->set_A(a);
}

Теперь из того, что я слышал, когда и a, и b выходят за пределы области действия, а их счетчик ссылок равен 0, они пытаются освободить и уничтожить указанную память, но в этом случае они не могут этого сделать, потому что оба указывают на объекты имеют shared_ptr, которые имеют счетчик ссылок 1, что делает их неудаляемыми, теперь это правда?

Затем он говорит, что для решения этой проблемы я должен сделать shared_ptr в class B weak_ptr, теперь почему это так? он по-прежнему имеет счетчик ссылок, равный 1, не так ли? И даже со weak_ptr все еще остается shared_ptr<B> b_ptr;, который остается со счетчиком ссылок равным 1, так как его можно удалить?

Также упоминается, что weak_ptr нарушает строгую ссылку на владение, но как weak_ptr может не иметь права собственности, как он получит доступ к объекту?

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


person Alex    schedule 27.05.2020    source источник
comment
Finally I heard that a weak_ptr is a smart pointer which can use methods such as lock() or expired() to manage a shared_ptr Например, вы проводили какие-либо исследования?   -  person KamilCuk    schedule 27.05.2020
comment
@KamilCuk хорошо, я просто хотел быть уверенным, чтобы у меня в голове было четкое представление о том, почему они используются.   -  person Alex    schedule 27.05.2020


Ответы (1)


Со всеми std::shared_ptr у вас есть:

int main() {
    std::shared_ptr<A> a = std::make_shared<A>(); // ref_count_a = 1
    std::shared_ptr<B> b = std::make_shared<B>(); // ref_count_b = 1
    a->set_B(b); // ref_count_b = 2
    b->set_A(a); // ref_count_a = 2
} // ref_count_a = 1 && ref_count_b = 1
// memleak due to the cycle

С

class B {
    std::weak_ptr<A> a_ptr;
// ...
};

это становится:

int main() {
    std::shared_ptr<A> a = std::make_shared<A>(); // ref_count_a = 1
    std::shared_ptr<B> b = std::make_shared<B>(); // ref_count_b = 1
    a->set_B(b); // ref_count_b = 2
    b->set_A(a); // ref_count_a = 1 , weak_ref_a = 1
} // ref_count_a = 0 && ref_count_b = 1
// -> release a -> ref_count_b = 0
// -> release b (+ control block) -> weak_ref_a = 0
// -> release control block of a

Также упоминается, что weak_ptr нарушает сильную ссылку на владение, но как weak_ptr может не иметь права собственности, как он получит доступ к объекту?

Система управления поддерживает счетчик для shared_ptr (для освобождения объекта) и счетчик для weak_ptr для освобождения блока управления. weak_ptr извлекает shared_ptr благодаря контрольному блоку.

Наконец я услышал, что weak_ptr — это интеллектуальный указатель, который может использовать такие методы, как lock() или expired(), для управления shared_ptr, опять же, правильно ли это?

Да

person Jarod42    schedule 27.05.2020