weak_ptr 与循环引用一起使用

Use of weak_ptr with cyclic references

所以我很难理解为什么我们必须使用 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);
}

现在据我所知,当 ab 都超出范围并且它们的引用计数为 0 时,它们会尝试解除分配并销毁指向内存的指针,但在这种情况下它们不能这样做,因为两个指向的对象都有 shared_ptr 的引用计数为 1,这使得它们不可删除,现在是真的吗?

然后,它说要解决这个问题,我必须将 class B 中的 shared_ptr 变成 weak_ptr,这是为什么呢?它的引用计数仍然为 1,不是吗?即使 weak_ptr 仍然有 shared_ptr<B> b_ptr; ,它的引用计数仍然为 1,那么如何删除它呢?

它还提到 weak_ptr 破坏了强所有权引用,但是 weak_ptr 怎么会 没有所有权,它将如何访问该对象?

提前致谢。

所有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

Also it mentions that a weak_ptr breaks strong ownership reference but how can a weak_ptr have no ownership, how will it access the object?

控件为shared_ptr维护一个计数器(释放对象) 和一个 weak_ptr 的计数器来释放控制块。 weak_ptr 检索 shared_ptr 感谢控制块。

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, again is this correct?