shared_ptr虽然方便,但是它有着一个致命的缺陷就是循环引用问题,因为shared_ptr本身并没有能力解决这个问题,所以我们又引入了弱指针weak_ptr来辅助shared_ptr解决这个问题。


那么循环引用又是什么场景?

举个栗子:

假设现在我们要创建一个双向×××链表,但是这个链表的指针域全部都用shared_ptr维护:

struct Node

{

int _data;

shared_ptr<Node> _next;

shared_ptr<Node> _prev;

}


假设现在先创建两个结点,并用shared_ptr维护这两个结点:

shared_ptr<Node> sp1(new Node);

shared_ptr<Node> sp2(new Node);


现在将这两个指针互相连接:

sp1->_next=sp2;

sp2->prev=sp1;




为了解决循化引用问题,我们又引入了weak_ptr弱指针,用来辅助shared_ptr。注意weak_ptr不能单独使用,必须辅助shared_ptr才能使用。weak_ptr是一种不控制所指向对象生存周期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一但最后一个指向对象的shared_ptr被销毁,对象就会被销毁,即使有weak_ptr指向对象,对象还是会被释放。


例:

所以为了解决上面栗子中的循环引用问题,我们可以将指针域的智能指针声明为弱指针。

struct Node

{

int _data;

weak_ptr<Node> _next;

weak_ptr<Node> _prev;

}


二、定置删除器

一般情况下,我们都用智能指针是用来管理动态内存的,其实智能指针是用来管理资源的,资源很多,动态内存只是资源的一种,比如说我们可以用智能指针来管理文件,那么我们就不能用智能指针默认的删除器了,因为要管理文件的话最后是fclose,而不是delete,所以我们就必须自己定制一个删除器。


例:以管理文件为例,实现定置删除器。

要实现定置删除器,就要用到仿函数:仿函数就是将"()"重载。

//定置删除器的仿函数structFclose{voidoperator()(void*ptr){fclose((FILE*)ptr);cout<<"fclose()"<<endl;}};voidtest(){boost::shared_ptr<FILE>sp(fopen("test.txt","w"),Fclose());//调用构造函数构造一个匿名对象传递过去,文件正常关闭}再举一个栗子:用智能指针管理malloc开辟的动态内存,那么我们在释放的时候就要用free释放://定置删除器的仿函数structFree{voidoperator()(void*ptr){free(ptr);}};voidtest(){boost::shared_ptr<int>sp((int*)malloc(sizeof(int)),Free());//能够正确的释放空间}




三、简单的实现一个有定置删除器的shared_ptr


structFclose{voidoperator()(void*ptr){fclose((FILE*)ptr);cout<<"fclose()"<<endl;}};structFree{voidoperator()(void*ptr){free(ptr);cout<<"free()"<<endl;}};//默认删除器是deletestructDefaultDel{voidoperator()(void*ptr){deleteptr;cout<<"deleteptr"<<endl;}};template<typenameT,typenameD=DefaultDel>classSharedPtr//采用引用计数,实现一个可以有多个指针指向同一块内存的类模板,SharedPtr是类模板,不是智能指针类型{public:SharedPtr(T*ptr,Ddel=DefaultDel());SharedPtr(constSharedPtr<T,D>&sp);SharedPtr<T,D>&operator=(SharedPtr<T,D>sp);T&operator*();T*operator->();~SharedPtr();intCount(){return*_pCount;}private:voidRelease(){if(--(*_pCount)==0){_del(_ptr);delete_pCount;_ptr=NULL;_pCount=NULL;}}private:T*_ptr;int*_pCount;D_del;};template<typenameT,typenameD=DefaultDel>SharedPtr<T,D>::SharedPtr(T*ptr,Ddel):_ptr(ptr),_pCount(newint(1)),_del(del){}template<typenameT,typenameD=DefaultDel>SharedPtr<T,D>::SharedPtr(constSharedPtr<T,D>&sp){_ptr=sp._ptr;_pCount=sp._pCount;++(*_pCount);}template<typenameT,typenameD=DefaultDel>SharedPtr<T,D>&SharedPtr<T,D>::operator=(SharedPtr<T,D>sp){std::swap(sp._ptr,_ptr);std::swap(sp._pCount,_pCount);return*this;}template<typenameT,typenameD=DefaultDel>T&SharedPtr<T,D>::operator*(){return*_ptr;}template<typenameT,typenameD=DefaultDel>T*SharedPtr<T,D>::operator->(){return_ptr;}template<typenameT,typenameD=DefaultDel>SharedPtr<T,D>::~SharedPtr(){Release();}//测试用例voidtest(){SharedPtr<int>sp(newint(1));SharedPtr<FILE,Fclose>sp1(fopen("test.txt","w"),Fclose());SharedPtr<string,Free>sp3((string*)malloc(sizeof(string)),Free());}intmain(){test();system("pause");return0;}