您的位置:首页 > 其它

带引用计数智能指针

2016-01-21 12:44 357 查看


参考:shared_ptr实现,auto_ptr-实现

注1:std::shared_ptr带引用计数

注2:std::auto_ptr不带引用计数(但支持release方法,断开指向)

参考:http://blog.csdn.net/lollipop_jin/article/details/8499530
(Owed by: 春夜喜雨http://blog.csdn.net/chunyexiyu)

1. 什么是智能指针

智能指针通常使用如下

std::shared_ptr
<CDemo> ipDemo = new CDemo;

通常提供

.get() method获取裸指针

operator ->同CDemo->使用效果一致

 

智能指针使用的过程中,不需要对ipDemo进行手动的释放,如果非要手动释放,也不能采用通常的方式

delete ipDeom.get() (错误) ---会引发重复释放的崩溃,原因是手动释放掉了,智能指针也会释放一次。

可以使用

ipDemo = nullptr;

ipDeom.reset(nullptr)来进行手动释放,或者是什么都不做,等待智能指针自动释放

 

2. 智能指针实现(带引用计数)

智能指针实现的原理是

存储引用计数

同时共享引用计数内存地址

(注意shared_ptr是用引用计数的,auto_ptr是无引用计数的)

 

实现这个有两种方法:

一种引用计数放入到智能指针类中,通过new实现,智能指针存储new出的地址

一种引用计数放入到类中

 

第一种:

智能指针需要实现:(参考如下代码)

引用计数,在合适的时机删除指针 (申请内存,从而进行计数共享)

Copy构造
  (定义时:= new时,或是等于另一个时)

operator =   (定义后,再赋值情况)

operator ->  (使用->时的情况处理)

.get()方法  (返回裸指针)

当前自己写的一个指针指针的实现参考下面的代码段。

 

第二种:

需要类里面提供计数,指针类调用类里的计数

支持智能指针的类需要实现

计数变量

提供addRef/ReleaseRef/QueryRef方法

智能指针实现

构造、析构调用类的addRef/ReleaseRef/QueryRef,在合适的时机删除指针

Copy构造

operator =

operator ->

.get()

 

 

第一种的样例实现

#pragmaonce

 

template <classT>

classCMySharedPtr

{

public:

   //构造时置为空

   CMySharedPtr()
:m_pRefCount(nullptr),m_pPointer(nullptr)
{}

   //析构时,检查计数,释放内存

   ~CMySharedPtr()

   {

       //释放原有

       freeCurrentPointer();

   }

   CMySharedPtr(T*pValue)

   {

       //构造

       createNewPointer(pValue);

   }

 

   CMySharedPtr(CMySharedPtr&ipValue)

   {

       // Copy构造

       CopyAutPtr(ipValue);

   }

 

 

public:

   T*get()

   {

       returnm_pPointer;

   }

 

   voidoperator
=(T*pValue)

   {

       if
(pValue ==
nullptr)

       {

           //置空-释放原有

           freeCurrentPointer();

       }

       else

       {

           //释放原有

           freeCurrentPointer();

 

           //申请新的

           createNewPointer(pValue);

       }

   }

   

   voidoperator
= (CMySharedPtr&ipValue)

   {

       //引用计数地址相同:意味着指向同一地址

       if
(ipValue.m_pRefCount
== m_pRefCount)

       {

           return;

       }

 

       //释放原有

       freeCurrentPointer();

 

       //申请新的

       CopyAutPtr(ipValue);

   }

 

   //重载->符号

   T*operator
->()

   {

       return
(get());

   }

 

protected:

   //通过一个指针构造另一个

   voidCopyAutPtr(CMySharedPtr&ipValue)

   {

       //计数加一

       m_pRefCount
=ipValue.m_pRefCount;

       //指针有效时加一

       if
(m_pRefCount !=
nullptr)

           (*m_pRefCount)++;

       //指针指向

       m_pPointer
=ipValue.m_pPointer;

   }

 

   //申请新指针

   template
<classT>

   voidcreateNewPointer(T*pValue)

   {

       m_pRefCount
=newint();

       *m_pRefCount
= 1;

       m_pPointer
=pValue;

   }

 

   //释放原有指针

   voidfreeCurrentPointer()

   {

       //存在时进行释放

       if
(m_pPointer !=
nullptr &&m_pRefCount
!=nullptr)

       {

           if
(*m_pRefCount > 1)

           {

               (*m_pRefCount)--;

           }

           elseif
(*m_pRefCount == 1)

           {

               *m_pRefCount
= 0;

               deletem_pPointer;

               deletem_pRefCount;

           }

       }

 

       //置初值

       m_pPointer
=nullptr;

       m_pRefCount
=nullptr;

   }

 

private:

   int*m_pRefCount;

   T*m_pPointer;

};

 
 

3. 智能指针的使用

智能指针使用时,直接使用即可,不用关心它的释放。

 

 

classDemo

{

public:

   Demo()

   {

       printf(("Demo
Create\n"));

   }

   ~Demo()

   {

       printf(("Demo
Delete\n"));

   }

public:

   voidShow()

   {

       printf(("Call
Demo Show\n"));

   }

};

voidTestCode()

{

   CMySharedPtr<Demo>ipValue
=newDemo();
//构造

   ipValue->Show();                      //
调用operator->

 

   CMySharedPtr<Demo>ipValue2
=ipValue; // copy构造

   ipValue2
=ipValue;                  //
调用operator =

   ipValue->Show();

}
 

 

4. 两种实现的区别

第一种实现,智能指针中存储引用计数,能支持所有的类型

第二种显现,类中存储引用计数,智能指针只能支持实现计数的类

 

第一种实现,不支持:(无论是使用auto_ptr还是shared_ptr,都永远不要写这样的代码)

Deom* pa = new A;
CMySharedPtr<Deom> ptr_a_1(pa);
CMySharedPtr<Deom> ptr_a_2(pa);
 

会导致重复释放。

 
第二种实现,支持上面那种,因为计数存储在类中,上面的代码,会让计数=2,不会产生重复释放的问题。

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: