智能指针shared_ptr 用引用计数实现看起来不错,但却存在问题。
1、引用计数更新存在着线程安全;
2、循环引用--使用一个弱引用智能指针(weak_ptr)来打破循环引用(weak_ptr不增加引用计数)
3、定置删除器和空间分配器
比如打开一个文件的关闭,用malloc开辟出来的空间,用引用计数实现会出现问题。
对改变引用计数时加锁可以解决引用计数更新存在着线程安全。
循环引用问题
#include<iostream> using namespace std; #include<memory>//库中包含shared_ptr struct ListNode { shared_ptr<ListNode> _prev; shared_ptr<ListNode> _next; ~ListNode() { cout << "~ListNode()" << endl; } }; void Test2() { shared_ptr<ListNode> cur(new ListNode);//1 shared_ptr<ListNode> next(new ListNode);//2 cout << "cur->" << cur.use_count() << endl;//use_count返回shared_ptr的引用计数 cout << "next->" << next.use_count() << endl; cur->_next = next;//3 next->_prev = cur;//4 cout << "cur->" << cur.use_count() << endl; cout << "next->" << next.use_count() << endl; } //经过语句1、2之后cur和next的引用计数为1,经过语句1、2后引用计数为2。 //但是最后两个对象均不能释放,因为cur的要释放的前提是next释放,而next的释放又依赖于cur的释放,最后就形成了循环引用。 //weak_ptr(弱引用智能指针)会对引用计数会做特殊处理解决这个问题。 struct ListNode { weak_ptr<ListNode> _prev; weak_ptr<ListNode> _next; ~ListNode() { cout << "~ListNode()" << endl; } };
定置删除器和空间分配器(ps:空间分配器的定置特殊场景下才会这样使用)
如果指针是一个指向文件类型的,在析构函数中只需关闭文件即可,而不是释放空间;如果空间是通过malloc开辟出来的,那么在析构函数中要调用free函数,而不是delete操作符。上述问题通过仿函数就可以解决。具体代码如下:
template<class T> class Del { public: void operator() (const T *ptr) { delete ptr; } }; //仿函数实现FClose和Free struct FClose { void operator() (void* ptr) { cout << "Close" << endl; fclose((FILE*)ptr); } }; struct Free { void operator() (void* ptr) { cout << "Free" << endl; free(ptr); } }; template<class T,class Deleter=Del<T>> class SharedPtr { public: SharedPtr(T* ptr) :_ptr(ptr) , _pCount(new long(1)) {} SharedPtr(T* ptr,Deleter del) :_ptr(ptr) , _pCount(new long(1)) , _del(del) {} SharedPtr<T>& operator=(SharedPtr<T> sp) { swap(_ptr, sp._ptr); swap(_pCount, sp._pCount); return *this; } ~SharedPtr() { cout << "~SharedPtr()" << endl; Release(); } T& operator*() { return *_ptr; } T* GetPtr()//返回原指针_ptr { return _ptr; } T* operator->() { return _ptr; } void Release()//释放内存 { if (--(*_pCount) == 0) { _del(_ptr); delete _pCount; } } private: T* _ptr; long* _pCount; Deleter _del; }; void Test3() { //定制删除器和分配器 SharedPtr<int> sp(new int(6)); SharedPtr<FILE, FClose> sp1(fopen("test.text", "w"), FClose()); SharedPtr<int, Free> sp2((int*)malloc(sizeof(int)* 6), Free()); }
时间: 2024-10-24 15:06:37