问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

解决shared_ptr的循环引用

创作时间:
作者:
@小白创作中心

解决shared_ptr的循环引用

引用
CSDN
1.
https://blog.csdn.net/guaiguaiyalj/article/details/143248681

在实现智能指针shared_ptr中有一个问题就是循环引用的问题,对于循环引用看下面的图来理解:

  1. node1node2两个智能指针对象指向两个节点,引用计数变成1,我们不需要手动 delete
  2. node1_next指向node2node2_prev指向node1,引用计数变成2(因为我们定义的结构中_next_prev也是shared_ptr的智能指针对象)。
  3. node1node2析构,引用计数减1,但是_next还指向下一个节点。_prev还指向上 一个节点。
  4. 也就是说_next析构了,node2的引用计数变为0,就释放了;同理_prev析构了,node1就释放了。
  5. 但是_next属于node1的成员,node1释放了,_next才会析构,而node1_prev管理,_prev 属于node2成员,所以这就叫循环引用,谁也不会释放。

再换个角度理解:

假如这里只有一个指向:node1->_next = node2;这样node1的计数为1,node2的计数为2,node1node2析构就会让node1的计数见减为0,node2减为1,然后node1计数为0释放,同时也会让node1的成员_next析构,_next的析构就会导致node2的计数减为0,这样node2也会释放,就不会有循环引用的问题。

我们这次要解决循环引用,就要把结构体中的_next_prev不要计数就可以解决,那样node1node2析构时资源也就释放了。解决方案:在引用计数的场景下,把节点中的_prev_next改成weak_ptr就可以了。原理就是,node1->_next = node2node2->_prev = node1时,weak_ptr_next_prev不会增加node1node2的引用计数。

template<class T>
class weak_ptr
{
public:
    weak_ptr()
        :_ptr(nullptr)
    {}
    weak_ptr(const shared_ptr<T>& sp)
        :_ptr(sp.get())
    {}
    weak_ptr<T>& operator=(const shared_ptr<T>& sp)
    {
        _ptr = sp.get();
        return *this;
    }
    // 像指针一样
    T& operator*(){return *_ptr;}
    T* operator->(){return _ptr;}
private:
    T* _ptr;
};

这里拷贝构造和赋值都是对shared_ptr对象,也就是说只需要拷贝构造和赋值shared_ptr对象的_ptr就可以了。因为这是不同的类,_ptrshared_ptr中的私有成员,不可访问,有两种方式可以实现:1、友元类;2、在shared_ptr中写一个公有的成员函数get来获取_ptr

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号