c++中shared_ptr的循环引用问题如何解决

文章探讨了C++中的循环引用现象,特别是如何通过使用weak_ptr来避免共享计数器导致的对象泄露。它解释了shared_ptr和weak_ptr的工作原理,以及在引用计数为零时的行为差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.什么是循环引用

2.如何解决循环引用

3.weak_ptr 怎么解决循环引用的呢?

1.当shared_ptr的引用计数--时

2.当weak_ptr的引用计数--时

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值