目录
1.什么是循环引用
我们知道当 shared_ptr 的引用计数为零时,shared_ptr所指向的对象就会被释放
那么两个shared_ptr互相指向对方会发生什么呢?
循环引用简单例子
class B;
class A
{
public:
std::shared_ptr<B> ptr_to_b;
~A()
{
std::cout << "A is being destroyed" << std::endl;
}
};
class B
{
public:
std::shared_ptr<A> ptr_to_a;
~B()
{
std::cout << "B is being destroyed" << std::endl;
}
};
int main()
{
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
cout << a.use_count() << endl;
cout << b.use_count() << endl;
// 创建循环引用
a->ptr_to_b = b;
b->ptr_to_a = a;
cout << a.use_count() << endl;
cout << b.use_count() << endl;
return 0;
}
结果呢,shared_ptr 对象一直没被释放,因为引用计数一直不为零
没有 原对象没有调用析构函数
2.如何解决循环引用
我们只要把两个shared_ptr的其中一个换成weak_ptr就可以了
class B;
class A
{
public:
std::shared_ptr<B> ptr_to_b;
~A()
{
std::cout << "A is being destroyed" << std::endl;
}
};
class B
{
public:
std::weak_ptr<A> ptr_to_a;
~B()
{
std::cout << "B is being destroyed" << std::endl;
}
};
int main()
{
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
cout << a.use_count() << endl;
cout << b.use_count() << endl;
// 创建循环引用
a->ptr_to_b = b;
b->ptr_to_a = a;
cout << a.use_count() << endl;
cout << b.use_count() << endl;
return 0;
}
把一方换成 weak_prt 后 ,成功调用析构函数
3.weak_ptr 怎么解决循环引用的呢?
在STL的shared_ptr源码中我们可以发现一共有两个引用计数
一个是负责管理shared_ptr的指向的对象
(表示有多少个 shared_ptr 指向同一个对象)
一个是负责管理weak_ptr的
(表示有多少个 weak_ptr 指向同一个对象)
当我们使用weak_ptr去指向shared_ptr的时,我们并不会增加 shared_ptr 的引用计数,
而是增加weak_ptr的引用计数
1.当shared_ptr的引用计数--时
_Sp_counted_base<_S_single>::_M_release() noexcept
{
if (--_M_use_count == 0)
{
_M_dispose();//删除shared_ptr指向的原对象
if (--_M_weak_count == 0)
_M_destroy();//删除weak_ptr这个类
}
}
2.当weak_ptr的引用计数--时
_Sp_counted_base<_S_single>::_M_weak_release() noexcept
{
if (--_M_weak_count == 0)
_M_destroy();//weak_ptr这个类删除,并不删除原对象
}
我们可以发现 weak_ptr的引用计数为零时,并不删除shared_ptr指向的对象,
也就是说weak_ptr不参与操作目标
注意:当share计数为0时, 原对象直接被删除没有了,使用weak_ptr直接失效
bool
expired() const noexcept
{ return _M_refcount._M_get_use_count() == 0; }
这个源码就是 查看weak_ptr 是否失效,失效我们就delete