[置顶] 带引用计数智能指针



参考:shared_ptr实现,auto_ptr-实现

1std::shared_ptr带引用计数

2std::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. 智能指针实现(带引用计数)

智能指针实现的原理是

  1. 存储引用计数

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

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

 

实现这个有两种方法:

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

一种引用计数放入到类中

 

第一种:

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

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

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

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

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

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

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

 

第二种:

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

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

  1. 计数变量

  2. 提供addRef/ReleaseRef/QueryRef方法

智能指针实现

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

  2. Copy构造

  3. operator =

  4. operator ->

  5. .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;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif
CMySharedPtr<Deom> ptr_a_1(pa);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif
CMySharedPtr<Deom> ptr_a_2(pa);

 

会导致重复释放。

 

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


(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)


你可能感兴趣的:(智能指针,引用计数)