文章标题 boost指针的引用计数,以及引发的资源共享和boost指针的交叉问题
2017-06-29 19:16
821 查看
我们平常使用的指针也叫裸指针,大家都知道申请内存时我们需要手动申请,但是有时候会因为使用完而忘记释放资源而引起内存上的泄漏。 那么如何能保证我们手动申请的资源不会发生这种情况? boost指针,它可以让我们放心的去使用资源而不会发生内存泄漏问题。 其原理就是利用对象的生命周期,对裸指针进行封装达到目的。话不多说,上代码:
class CSmartPtr { public: CSmartPtr(T *ptr = NULL):mptr(ptr) {} ~CSmartPtr() { delete mptr; mptr = NULL; } private: int *mptr; }; int main() { CSmartPtr ptr1(new int); return 0; }
资源虽然得到了释放但是又产生了新的问题。 多个boost指针同时指向一个资源,资源会被重复释放还是会挂掉。 我们可以试想一下,如果我们对同一资源进行多次引用时可以记录一下它被引用了多少次。 那么再释放时,我们只在计数为1时对资源进行释放就可以解决这个问题。
这里我们可以采用库里的map来保存资源以及相应的引用计数。 为了更好体现封装,我们将map单独写一个类,并且提供了相应的引用计数操作方法。 class CResMap { public: void addRef(void *mptr) { map<void*,int>::iterator it = mResMap.find(mptr); if(it != mResMap.end()) { it->second++; return; } //mResMap.insert(make_pair(mptr, 1)); mResMap[mptr] = 1; } void delRef(void *mptr) { map<void*, int>::iterator it = mResMap.find(mptr); if(it != mResMap.end()) { if(it->second-- == 0) mResMap.erase(it); return; } } int getRef(void *mptr) { map<void*, int>::iterator it = mResMap.find(mptr); if(it != mResMap.end()) { return it->second; } return 0; } static CResMap* getInstance() { static CResMap mres; return &mres; } private: CResMap(){} map<void*,int> mResMap; }; template<typename T> class CSmartPtr { public: CSmartPtr(T *ptr = NULL):mptr(ptr) { if(mptr != NULL) addRef(); } ~CSmartPtr() { delRef(); if(getRef() == 0) { delete mptr; mptr=NULL; } } private: T *mptr; static CResMap *mResMap; void addRef() { mResMap->addRef(mptr); } void delRef() { mResMap->delRef(mptr); } int getRef() { return mResMap->getRef(mptr); } };
现在我们已经可以达到了可以对同一资源的正确释放。但是因为我们用的是模板类。 所以当实例化两个及以上的类时,两张表中同一资源和引用计数,那么此时俩类都有程序还是会挂掉。 int *p = new int; CSmartPtr<int> ptr1(p); CSmartPtr<char> ptr2((char*)p); //结束的时候,还会挂在析构那里 解决办法其实已经写入代码中了(单例模式),就是让不同的类型也共享同一个表,这样就不会出现引用计数失效。
最后一个问题,boost指针的交叉问题。上图给大家解释一下:
显然当我们执行完程序时,发现析构函数没有被调用,也就是资源没有被释放。 两个资源里面的智能指针互相指向对方,这时候就产生问题(你不是释放,我不释放),导致双方的资源引用计数都是一,都无法释放掉。
这里就引出了shared_ptr和weak_ptr。(主要避免循环引用导致内存泄漏) 使用weak_ptr避免shared_ptr的循环引用,weak_ptr在访问资源前必须先lock,提升为强指针才可以操作资源。 这里我们可以尝试简单模仿一下库里的办法。 template<typename T> class CWeakPtr { public: CWeakPtr(T *ptr = NULL):mptr(ptr){}; CWeakPtr(const CSmartPtr<T> &src) { mptr = src.mptr; } CWeakPtr& operator=(const CSmartPtr<T> &src) { mptr = src.mptr; return *this; } CSmartPtr<T> lock() { return CSmartPtr<T>(CWeakPtr<T>(mptr)); } friend class CSmartPtr<T>; private: T *mptr; }; template<typename T> CSmartPtr<T>::CSmartPtr(const CWeakPtr<T> &w):mptr(w.mptr) { if (getRef()>0) { addRef(); } }
我们尝试提升一下,发现确实没有让引用计数增加。 CSmartPtr<A> ptra(new A()); cout<<ptra.use_count()<<endl; CWeakPtr<A> ptrb(ptra); cout<<ptra.use_count()<<endl;
“`
这次我们提升一下看看,确实成功了。
这样可以解决boost指针的交叉问题。其实以后可以大胆放心的去使用shared_ptr,因为它是线程安全的,是原子操作,不会发生同时加减的情况。
相关文章推荐
- C++的引用计数j控制智能指针——>Java的引用计数管理共享对象
- javascript 中的声明作用域范围以及指针引用的问题。
- 智能指针的实现--使用引用计数实现以及原理
- C++ 中的指针、引用以及函数调用中的问题
- 转载一篇觉得不错的文章,关于并发访问资源共享问题
- 跨域资源共享CORS以及在zepto中使用遇到的问题
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- C#中引用第三方ocx控件引发的问题以及解决办法
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- C++ 智能指针——简单实现以及循环引用问题
- C++ — 智能指针的简单实现以及循环引用问题
- 智能指针的交叉引用问题及解决方法
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- 智能指针和引用计数以及String的C++实现
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
- 智能指针引用计数问题
- C++ — 智能指针的简单实现以及循环引用问题
- ASP.NET AJAX 1.0资源连接以及对一些常见问题的答复
- Windows与VMware下Linux的文件共享问题以及解决办法