c++:分析智能指针shared_ptr存在的循环引用的缺陷
来源:互联网 发布:树莓派zerow ubuntu 编辑:程序博客网 时间:2024/06/08 12:36
首先来回顾一下智能指针的历史:
以及在《c++:分析智能指针与发展历史》一文中模拟实现的简单的shared_ptr:
template <class T>class SharedPtr{public: SharedPtr(T* ptr) :_ptr(ptr) , _refCount(new int(1)) {} SharedPtr(SharedPtr<T>& sp) :_ptr(sp._ptr) , _refCount(sp._refCount) { ++(*_refCount); } SharedPtr<T>& operator=(SharedPtr<T>& sp) { if (_ptr != sp._ptr) { if (--(*_refCount) == 0) { delete _ptr; delete _refCount; } _ptr = sp._ptr; _refCount = sp._refCount; ++(*_refCount); } return *this; } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } ~SharedPtr() { if (--(*_refCount) == 0) { delete _ptr; delete _refCount; } }private: T* _ptr; int* _refCount;};
shared_ptr不仅体现了RAII思想,而且多了一个int*型成员变量,用来引用计数,解决了浅拷贝的两个问题。(具体看我之前写的c++写时拷贝对引用计数有解析,这里我只分析shared_ptr的循环引用的问题)
那么这么完美的智能指针,到底有什么问题呢?
我来创建一个场景:
struct ListNode{ ListNode() :_data(1) , _next(NULL) , _prev(NULL) {} int _data; SharedPtr<ListNode> _next; Shared_ptr<ListNode> _prev;};
这是一个简单的双向链表类。
void TestSharedPtrError(){ SharedPtr<ListNode> cur(new ListNode); SharedPtr<ListNode> next(new ListNode); cur->_next = next; next->_prev = cur;}
接下来,我利用SharedPtr实例化出对象,如图:
首先 SharedPtr cur(new ListNode);
SharedPtr next(new ListNode);
这两句代码构造了两个对象cur和next,它们分别有_ptr和_refcount,它们的_ptr指向一个ListNode类型的对象,_*refcount为1。
两个对象内有分别有两个对象_next和_prev它们的_ptr初始化为NULL,_refcount为1(参见构造函数)请看监视:
这两段代码:
cur->_next = next;
next->_prev = cur;
调用了operator=,因为_next和_prev已经被初始化。
所以说,在operaotor=函数里,我已经标明了指向关系,并且现在cur和next的引用计数都变为2。
请看监视:
出了cur和next作用域,会调用析构函数,那么会先调用_next的析构函数,再调用_cur的析构函数,但是这会陷入一个循环,因为释放关系中你的释放需要我,我的释放需要你,谁都不肯放手,自然会出现内存泄漏。 如何解决问题,引入了wead_ptr,这里我也是简单的模拟实现它:
template <class T>class WeakPtr{public: WeakPtr(const SharedPtr<T>& sp) :_ptr(sp._ptr) {} WeakPtr<T>& operator=(SharedPtr<T>& sp) { _ptr = sp._ptr; return *this; }private: T* _ptr;};
然后对以上代码进行修改:
struct ListNode{ ListNode() :_data(1) , _next(NULL) , _prev(NULL) {} int _data; WeakPtr<ListNode> _next; WeakPtr<ListNode> _prev;};
那么
void TestSharedPtrError(){ SharedPtr<ListNode> cur(new ListNode); SharedPtr<ListNode> next(new ListNode); cur->_next = next; next->_prev = cur;}
就是Shraed_ptr的对象赋值给WeakPtr的对象。
这样的话出了作用域调用析构函数,就可以清理干净,不会存在内存泄漏。
- c++:分析智能指针shared_ptr存在的循环引用的缺陷
- shared_ptr,带引用计数的智能指针
- 关于boost 库 shared_ptr 智能指针的循环引用【2013.10.22】
- 智能指针的模拟实现shared_ptr 循环引用 定置删除器
- 智能指针的缺陷
- 智能指针 shared_ptr 的使用方法
- 智能指针shared_ptr的实现
- 智能指针shared_ptr的用法
- 智能指针shared_ptr的用法
- 智能指针的死穴 -- 循环引用
- 智能指针的死穴 -- 循环引用
- 智能指针的死穴 -- 循环引用
- 智能指针的死穴 -- 循环引用
- boost的shared_ptr循环引用
- boost的shared_ptr循环引用
- boost的shared_ptr循环引用
- 智能指针原理分析与自己的shared_ptr实现
- 智能指针的循环引用和如何解决循环引用
- 习题7.3
- 共同学习Java源代码-数据结构-HashMap(十二)
- 图
- 深入Web请求过程
- java编程思想---第四章(控制执行流程)
- c++:分析智能指针shared_ptr存在的循环引用的缺陷
- 梁胜博士:写给程序员的话
- Dubbo和Spring Cloud微服务架构对比
- 自定义View实现索引效果
- 不定时更新-android学习之路
- 14个你可能不知道的javascript调试技巧
- M6G2C 飞思卡尔 嵌入式linux 内核驱动编译注意点
- 循环嵌套的应用
- 【Scikit-Learn 中文文档】概率校准