智能指针的模拟实现shared_ptr 循环引用 定置删除器

来源:互联网 发布:windows更新消失 编辑:程序博客网 时间:2024/05/17 23:58

auto_ptr与scoped_ptr的实现见本人的上篇博客。

三、shared_ptr

shared_ptr的实现原理是通过引用计数来实现,只有当引用计数为1时才释放空间,否则只需将引用计数减1.拷贝和赋值将引用计数加1,具体代码如下:

template <typename T>class SharedPtr{public:SharedPtr();SharedPtr(T* ptr);SharedPtr(const SharedPtr<T>& ap);~SharedPtr();//SharedPtr<T>& operator=(const SharedPtr<T>& ptr);//传统写法SharedPtr<T>& operator=(SharedPtr<T> ap);//现代写法T& operator*()const;T* operator->()const;long GetCount()const;T* GetPtr()const;protected:void _Realease();protected:T* _ptr;long* _pCount;};template <typename T>SharedPtr<T>::SharedPtr() :_ptr(NULL), _pCount(new long(1)){}template <typename T>SharedPtr<T>::SharedPtr(T* ptr) : _ptr(ptr), _pCount(new long(1)){}template <typename T>SharedPtr<T>::SharedPtr(const SharedPtr<T>& ap) : _ptr(ap._ptr), _pCount(ap._pCount){++(*this->_pCount);}template <typename T>SharedPtr<T>::~SharedPtr(){this->_Realease();}//template <typename T>//传统写法//SharedPtr<T>& SharedPtr<T>::operator=(const SharedPtr<T>& ap)//{//if (this->_ptr != ap._ptr)//{//this->_Realease();//this->_ptr = ap._ptr;//this->_pCount = ap._pCount;//++(*this->_pCount);//}//return *this;//}template <typename T>//现代写法SharedPtr<T>& SharedPtr<T>::operator=(SharedPtr<T> ap){swap(this->_ptr, ap._ptr);swap(this->_pCount, ap._pCount);return *this;}template <typename T>T& SharedPtr<T>::operator*()const{return *(this->_ptr);}template <typename T>T* SharedPtr<T>::operator->()const{return this->_ptr;}template <typename T>long SharedPtr<T>::GetCount()const{return *(this->_pCount);}template <typename T>T* SharedPtr<T>::GetPtr()const{return this->_ptr;}template <typename T>void SharedPtr<T>::_Realease(){if (--(*this->_pCount) == 0){delete this->_ptr;delete this->_pCount;}}

然而上面用引用计数实现的简化版看起来不错,但却存在以下问题:

1、引用计数更新存在着线程安全

2、循环引用

3、定置删除器,比如要关闭一个文件,用malloc开辟出来的空间,上述代码均会出现问题

问题1的解决需要对改变引用计数时加锁。我们暂时不讨论,一下我们主要看第二个和第三个问题。

循环引用:

比如有以下结构体和主函数:

struct ListNode{shared_ptr<ListNode> _prev; //shared_ptr为库文件中实现的,只需包memory即可使用shared_ptr<ListNode> _next;~ListNode(){cout << "~ListNode()" << endl;}};int main(){shared_ptr<ListNode> prev; //语句1shared_ptr<ListNode> next; //语句2prev->_next = next;        //语句3next->_prev = prev;        //语句4}

经语句1、2之后prev的引用计数为1,经3、4后为2,但是最后两个对象均不能释放,因为prev的要释放的前提是next释放,而next的释放又依赖于prev的释放。最后就形成了循环引用,谁都是放不了。解决方案如下:

struct ListNode{weak_ptr<ListNode> _prev;weak_ptr<ListNode> _next;~ListNode(){cout << "~ListNode()" << endl;}};

因为weak_ptr(弱引用智能指针)会对引用计数会做特殊处理(上述情况不加1)。

定置删除器和空间分配器(ps:空间分配器的定置特殊场景下才会这样使用)

eg:如果指针是一个指向文件类型的,在析构函数中只需关闭文件即可,而不是释放空间;如果空间是通过,malloc出来的,那么在析构函数中要调用free函数,而不是delete操作符。上述问题通过仿函数就可以解决。具体代码如下:

template <typename T,class Deleter = Del<T>>class SharedPtr{public:SharedPtr(T* ptr);SharedPtr(T* ptr, Deleter del);SharedPtr(const SharedPtr<T, Deleter>& ap);~SharedPtr();//SharedPtr<T, Deleter>& operator=(const SharedPtr<T, Deleter>& ptr);//传统写法//现代写法SharedPtr<T, Deleter>& operator=(SharedPtr<T, Deleter> ap);T& operator*()const;T* operator->()const;long GetCount()const;T* GetPtr()const;protected:void _Realease();protected:T* _ptr;long* _pCount;Deleter _del;};template <typename T, class Deleter = Del<T>>SharedPtr<T, Deleter>::SharedPtr(T* ptr) :_ptr(ptr), _pCount(new long(1)){}template <typename T, class Deleter = Del<T>>SharedPtr<T, Deleter>::SharedPtr(T* ptr, Deleter del) : _ptr(ptr), _pCount(new long(1)), _del(del){}template <typename T, class Deleter = Del<T>>SharedPtr<T, Deleter>::SharedPtr(const SharedPtr<T, Deleter>& ap) : _ptr(ap._ptr), _pCount(ap._pCount), _del(ap._del){++(*this->_pCount);}template <typename T, class Deleter = Del<T>>SharedPtr<T, Deleter>::~SharedPtr(){this->_Realease();}//template <typename T, class Deleter = Del<T>>//传统写法//SharedPtr<T, Deleter>& SharedPtr<T, Deleter>::operator=(SharedPtr<T, Deleter> ap)//{//if (this->_ptr != ap._ptr)//{//this->_Realease();//this->_ptr = ap._ptr;//this->_pCount = ap._pCount;//++(*this->_pCount);//}//return *this;//}template <typename T, class Deleter = Del<T>>//现代写法SharedPtr<T, Deleter>& SharedPtr<T, Deleter>::operator=(SharedPtr<T, Deleter> ap){swap(this->_ptr, ap._ptr);swap(this->_pCount, ap._pCount);swap(this->_del, ap._del);return *this;}template <typename T, class Deleter = Del<T>>T& SharedPtr<T, Deleter>::operator*()const{return *(this->_ptr);}template <typename T, class Deleter = Del<T>>T* SharedPtr<T, Deleter>::operator->()const{return this->_ptr;}template <typename T, class Deleter = Del<T>>long SharedPtr<T, Deleter>::GetCount()const{return *(this->_pCount);}template <typename T, class Deleter = Del<T>>T* SharedPtr<T, Deleter>::GetPtr()const{return this->_ptr;}template <typename T, class Deleter = Del<T>>void SharedPtr<T, Deleter>::_Realease(){if (--(*this->_pCount) == 0){_del(_ptr);delete this->_pCount;}}
0 0
原创粉丝点击