智能指针仿真-003-共享智能指针
2015-09-20 15:42
204 查看
1. 概述
本篇对共享所有权的智能指针进行仿真。
仿真指针主要有:boost/c++ 11 tr1中的shared_ptr、weak_ptr。
boost与c++ 11 tr1的关系这里稍微做一下类比,shared_ptr在boost中时可以认为是储君(准标准),进入到了tr1之后就正名了就算正式登基了是完全标准的了。
2. this指针的探讨
this指针是编译器默认生成到成员函数中的,类型为T* const this。
例如写一个简单的成员函数。
编译器处理起来如下。
接下来要思考的问题就是。
1) this指针可以删除吗?
2) 执行删除操作有引发哪些问题?
2.1. delete this源码
成员函数内进行delete this操作源码如下。
2.2. delete this栈检测
对于栈分配,进行delete检测。
运行程序会报错。
2.3. delete this堆检测
对于堆分配,进行delete检测。
运行程序后释放内存正常。
2.4. delete this总结
对delete this做下总结。
1) 对栈上分配的空间则不要调用。
2) 可以采用这种方式来释放堆中分配内存。
3) 调用对应接口后,指针将变为野指针,不可再进行后续操作。
3. shared_ptr仿真
3.1. shared_ptr相关问题
带着如下问题来做仿真实现。
1) shared_ptr实现原理?
2) shared_ptr是否就意味着一统天下?
3) shared_ptr使用中的坑?
3.2. 引用计数类仿真
Shared_ptr中采用引用计数来进行所有权共享,当引用计数为0时进行资源释放。首先进行引用计数类仿真MyRefCount.h。
3.3. 共享指针基类仿真
Weak_ptr和shared_ptr的共用基类进行仿真MyPtrBase.h。
3.4. weak_ptr及shared_ptr仿真源码
对应实现类MySharedPtr.h。
3.5. 仿真指针使用源码
对指针进行使用。
输出结果:
3.6. shared_ptr环状引用示例
shared_ptr出现环状引用的话将出现资源泄漏。采用自引用示例来检测。
运行结果:
3.7. weak_ptr解决环状引用
weak_ptr引用不会引起计数增加,可用来破环状引用。
运行结果:
3.8. shared_ptr总结
通过仿真源码,对shared_ptr总结如下。
1) 共享型智能指针通过引用计数方式来实现所有权共享,但同时增加了程序复杂度和运行性能。
2) 避免出现环状引用,这将会引起资源泄漏。
3) weak_ptr是shared_ptr的助手,是弱指针,可用于解除环状引用,但不支持原生指针获取以及->和*操作。
本篇对共享所有权的智能指针进行仿真。
仿真指针主要有:boost/c++ 11 tr1中的shared_ptr、weak_ptr。
boost与c++ 11 tr1的关系这里稍微做一下类比,shared_ptr在boost中时可以认为是储君(准标准),进入到了tr1之后就正名了就算正式登基了是完全标准的了。
2. this指针的探讨
this指针是编译器默认生成到成员函数中的,类型为T* const this。
例如写一个简单的成员函数。
class A { public: void func(){} };
编译器处理起来如下。
void func(A* const this);
接下来要思考的问题就是。
1) this指针可以删除吗?
2) 执行删除操作有引发哪些问题?
2.1. delete this源码
成员函数内进行delete this操作源码如下。
class CTest { public: CTest() : m_nVal(0){} ~CTest() {} /// @brief 释放自身内存 void Release() {delete this;} private: int m_nVal;///< 测试成员变量 };
2.2. delete this栈检测
对于栈分配,进行delete检测。
void TestStackDelete() { /// @brief 检测栈释放 CTest test; test.Release(); } int _tmain(int argc, _TCHAR* argv[]) { TestStackDelete(); return 0; }
运行程序会报错。
2.3. delete this堆检测
对于堆分配,进行delete检测。
void TestHeapDelete() { /// @brief 检测堆释放 CTest* pTest = new CTest; pTest->Release(); } int _tmain(int argc, _TCHAR* argv[]) { TestHeapDelete(); return 0; }
运行程序后释放内存正常。
2.4. delete this总结
对delete this做下总结。
1) 对栈上分配的空间则不要调用。
2) 可以采用这种方式来释放堆中分配内存。
3) 调用对应接口后,指针将变为野指针,不可再进行后续操作。
3. shared_ptr仿真
3.1. shared_ptr相关问题
带着如下问题来做仿真实现。
1) shared_ptr实现原理?
2) shared_ptr是否就意味着一统天下?
3) shared_ptr使用中的坑?
3.2. 引用计数类仿真
Shared_ptr中采用引用计数来进行所有权共享,当引用计数为0时进行资源释放。首先进行引用计数类仿真MyRefCount.h。
#pragma once /// @brief 引用计数类 template<class _Ty> class CMyRefCount { public: CMyRefCount(_Ty *_Px) : m_nUses(1) , m_nWeaks(1) , _Ptr(_Px) {} /// @brief 增加强引用计数 void _Incref() {++m_nUses;} /// @brief 增加弱引用计数 void _Incwref() {++m_nWeaks;} /// @brief 减少强引用计数 void _Decref() { --m_nUses; if (0 == m_nUses) { _Destroy(); _Decwref(); } } /// @brief 减少弱引用计数 void _Decwref() { --m_nWeaks; if (0 == m_nWeaks) { _Delete_this(); } } /// @brief 获取强引用计数 long _Use_count() const {return (m_nUses);} /// @brief 指针是否已释放 bool _Expired() const {return (0==m_nUses);} private: void _Destroy() {delete _Ptr;} void _Delete_this() {delete this;} private: long m_nUses;///< 强引用次数 long m_nWeaks;///< 弱引用次数 _Ty * _Ptr; };
3.3. 共享指针基类仿真
Weak_ptr和shared_ptr的共用基类进行仿真MyPtrBase.h。
#pragma once #include "MyRefCount.h" /// @brief shared_ptr/weak_ptr基类 template<class _Ty> class CMyPtrBase { typedef CMyPtrBase<_Ty> _Myt; public: /// @brief 获取强引用计数 long use_count() const { if (NULL == _Rep) {return 0;} return (_Rep->_Use_count()); } protected: CMyPtrBase() : _Ptr(nullptr) , _Rep(nullptr) {} /// @brief 指针是否已释放 bool _Expired() const { if (NULL == _Rep) {return true;} return (_Rep->_Expired()); } /// @brief 获取原生指针 _Ty *_Get() const {return (_Ptr);} /// @brief 减少强引用计数 void _Decref() { if (nullptr == _Rep) {return;} _Rep->_Decref(); } /// @brief 重置资源强引用 void _Reset(const _Myt& _Other) { _Reset(_Other._Ptr, _Other._Rep, false); } void _Reset(_Ty *_Other_ptr, CMyRefCount<_Ty> *_Other_rep, bool bInit) { /// @brief 初次赋值则不做增加操作 if (!bInit) { if (_Other_rep != nullptr) {_Other_rep->_Incref();}///< other强引用增加 } if (_Rep != nullptr) {_Rep->_Decref();}///< this强引用减少 _Rep = _Other_rep; _Ptr = _Other_ptr; } /// @brief 减少弱引用计数 void _Decwref() { if (nullptr == _Rep) {return;} _Rep->_Decwref(); } /// @brief 重置资源弱引用 void _Resetw(const _Myt& _Other) { _Resetw(_Other._Ptr, _Other._Rep); } void _Resetw(_Ty *_Other_ptr, CMyRefCount<_Ty> *_Other_rep) { if (_Other_rep != nullptr) {_Other_rep->_Incwref();}///< other弱引用增加 if (_Rep != nullptr) {_Rep->_Decwref();}///< this弱引用减少 _Rep = _Other_rep; _Ptr = _Other_ptr; } private: _Ty *_Ptr; ///< 持有指针 CMyRefCount<_Ty> *_Rep; ///< 引用计数 };
3.4. weak_ptr及shared_ptr仿真源码
对应实现类MySharedPtr.h。
#pragma once #include "MyPtrBase.h" template<class _Ty> class CMyWeakPtr; template<class _Ty> class CMySharedPtr; template<class _Ty> class CMySharedPtr : public CMyPtrBase<_Ty> { public: typedef CMySharedPtr<_Ty> _Myt; /// @brief 默认构造函数 CMySharedPtr() {} /// @brief 析构函数中释放资源 ~CMySharedPtr() { this->_Decref(); } /// @brief 显示声明传值构造函数 explicit CMySharedPtr(_Ty *_Px) { this->_Reset(_Px, new CMyRefCount<_Ty>(_Px), true); } /// @brief 拷贝构造函数 CMySharedPtr(const _Myt& _Other) { this->_Reset(_Other); } /// @brief 赋值操作符 _Myt& operator=(const _Myt& _Other) { this->_Reset(_Other); return (*this); } /// @brief 支持weak_ptr复制 /// 不支持weak_ptr赋值,需要通过lock来转获取share_ptr explicit CMySharedPtr(const CMyWeakPtr<_Ty>& _Other) { this->_Reset(_Other); } /// @brief 重置 void reset() { this->_Reset(nullptr, nullptr, false); } /// @brief 获取原生指针 _Ty *get() const {return (this->_Get());} /// @brief 仿真指针操作 _Ty *operator->() const { return (this->_Get());} _Ty &operator*() const { return (*this->_Get());} /// @brief 是否唯一持有资源 bool unique() const {return (this->use_count() == 1);} }; template<class _Ty> class CMyWeakPtr : public CMyPtrBase<_Ty> { typedef CMyWeakPtr<_Ty> _Myt; public: CMyWeakPtr() {} ~CMyWeakPtr() {this->_Decwref();} explicit CMyWeakPtr(const _Myt& _Other) {this->_Resetw(_Other);} CMyWeakPtr& operator=(const _Myt& _Other) { this->_Resetw(_Other); return (*this); } /// @brief shared_ptr支持 explicit CMyWeakPtr(const CMySharedPtr<_Ty>& _Other) {this->_Resetw(_Other);} CMyWeakPtr& operator=(const CMySharedPtr<_Ty>& _Other) { this->_Resetw(_Other); return (*this); } /// @brief 重置 void reset() {this->_Resetw(nullptr, nullptr, false);} /// @brief 资源释放还存在 bool expired() const {return (this->_Expired());} /// @brief 转化为shared_ptr CMySharedPtr<_Ty> lock() const { return (CMySharedPtr<_Ty>(*this)); } };
3.5. 仿真指针使用源码
对指针进行使用。
#include "stdafx.h" #include "MySharedPtr.h" #include <iostream> class CTest { public: CTest() {std::cout<<"CTest()"<<std::endl;} ~CTest() {std::cout<<"~CTest()"<<std::endl;} void test_print() {std::cout<<"test_print()"<<std::endl;} }; int _tmain(int argc, _TCHAR* argv[]) { CMySharedPtr<CTest> t1(new CTest); /// @brief 原生指针检测 t1->test_print(); (*t1).test_print(); std::cout<<t1.use_count()<<std::endl; { /// @brief 检测复制 CMySharedPtr<CTest> t2(t1); std::cout<<t1.use_count()<<std::endl; } std::cout<<t1.use_count()<<std::endl; { /// @brief 检测赋值 CMySharedPtr<CTest> t3; t3 = t1; std::cout<<t1.use_count()<<std::endl; } std::cout<<t1.use_count()<<std::endl; { /// @brief 检测weak_ptr CMyWeakPtr<CTest> w1(t1);///< weak_ptr不会增加引用计数 std::cout<<t1.use_count()<<std::endl; CMySharedPtr<CTest> t4(w1);///< 通过构造函数获取weak_ptr引用指针 std::cout<<t1.use_count()<<std::endl; CMySharedPtr<CTest> t5; //t5 = w1;///< 检测weak_ptr直接赋值会编译失败 t5 = w1.lock();///< 通过lock获取weak_ptr引用指针 std::cout<<t1.use_count()<<std::endl; } return 0; }
输出结果:
CTest() test_print() test_print() 1 2 1 2 1 1 2 3 ~CTest()
3.6. shared_ptr环状引用示例
shared_ptr出现环状引用的话将出现资源泄漏。采用自引用示例来检测。
#include "stdafx.h" #include "MySharedPtr.h" #include <iostream> class CSelfRefTest { public: CSelfRefTest() {std::cout<<"CSelfRefTest()"<<std::endl;} ~CSelfRefTest() {std::cout<<"~CSelfRefTest()"<<std::endl;} CMySharedPtr<CSelfRefTest> m_pTest; }; int _tmain(int argc, _TCHAR* argv[]) { /// @brief shared_ptr产生环形引用时将出现资源泄漏情况 /// 采用自引用示例来说明 CMySharedPtr<CSelfRefTest> p1(new CSelfRefTest); std::cout<<p1.use_count()<<std::endl; p1->m_pTest = p1;///< 进行自引用操作 std::cout<<p1.use_count()<<std::endl; return 0; }
运行结果:
CSelfRefTest() 1 2
3.7. weak_ptr解决环状引用
weak_ptr引用不会引起计数增加,可用来破环状引用。
#include "MySharedPtr.h" #include <iostream> class CSelfRefTest { public: CSelfRefTest() {std::cout<<"CSelfRefTest()"<<std::endl;} ~CSelfRefTest() {std::cout<<"~CSelfRefTest()"<<std::endl;} CMyWeakPtr<CSelfRefTest> m_pTest; }; int _tmain(int argc, _TCHAR* argv[]) { /// @brief shared_ptr产生环形引用时将出现资源泄漏情况 /// 采用weak_ptr来解决该问题 CMySharedPtr<CSelfRefTest> p1(new CSelfRefTest); std::cout<<p1.use_count()<<std::endl; p1->m_pTest = p1;///< 进行自引用操作 std::cout<<p1.use_count()<<std::endl; return 0; }
运行结果:
CSelfRefTest() 1 1 ~CSelfRefTest()
3.8. shared_ptr总结
通过仿真源码,对shared_ptr总结如下。
1) 共享型智能指针通过引用计数方式来实现所有权共享,但同时增加了程序复杂度和运行性能。
2) 避免出现环状引用,这将会引起资源泄漏。
3) weak_ptr是shared_ptr的助手,是弱指针,可用于解除环状引用,但不支持原生指针获取以及->和*操作。
相关文章推荐
- PHPExcel 读excel
- linux常用命令(38):iostat 命令
- 二叉堆
- Android贴吧系统学习-----悬浮布局出现的bug--android.view.WindowManager$BadTokenException:
- Android(异步任务) AsyncTask
- 使用dxNavBar动态创建应用程序菜单
- 数值
- Android View生命周期
- code::blocks的使用
- easyUI之Combo
- [LeetCode]1. 2Sum 数组中和为特定值的两个数
- iOS代码实践总结
- tchar.h及TCHAR数据类型介绍
- Windows安装Nodejs的模块和引用问题(cannot find moudel "xxx")?
- JSP之response对象使用
- CUDA和OpenCL的区别
- linux 查看网卡流量六种方法
- 在CentOS 6.4中编译安装gcc 4.8.1
- 网卡
- 【UML】概述