使用带有循环引用的weak_ptr

Use of weak_ptr with cyclic references

本文关键字:weak ptr 引用 循环      更新时间:2023-10-16

所以我很难理解为什么我们必须使用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 时,它们会尝试释放并销毁指向内存的内容,但在这种情况下,它们无法做到这一点,因为两者都指向对象具有引用计数为 1 的shared_ptr,这使得它们不可删除, 这是真的吗?

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

它还提到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

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

控件维护shared_ptr的计数器(释放对象( 以及一个计数器,供weak_ptr释放控制块。 weak_ptr通过控制块检索shared_ptr。

最后我听说weak_ptr是一个智能指针,可以使用 lock(( 或 expire(( 等方法来管理shared_ptr,这又是对的吗?

是的