c++:智能指针shared_ptr

先前的文章我们讲过了智能指针的概念等一系列问题,下面我们直接来看智能指针

1.带有引用计数的智能指针  (Shared_ptr)同时也是强智能指针

所谓的引用计数,就是有多少个智能指针对象管理这个堆内存。引用计数的作用是做所有对象共享的。

不可以写为普通的成员变量,要写成静态的成员变量

 

我们用一个引用计数管理器来实现Shared_ptr智能指针:

设计思路:

将引用计数管理器设计为数组,用地址和引用计数来当作节点记录堆内存,因为对地址只做一个简单的计数管理,所以用void*,引用计数用int,在智能指针类中,给出一个私有的成员变量mptr,一个静态的成员变量(引用计数管理器)static RefManage。给定一个对象rm。

但智能指针与引用计数管理器属于两种不同的类,为了实现它们之间的信息交互就要调用对方的接口。在引用计数管理器中预留一些接口(下面会给出接口的类型),注意堆上的操作都在智能指针类,通过下面的几个接口可以来进行对

智能指针类的操作,智能指针类中成员变量,静态变量已经设置好。智能指针类构造函数中,引用计数初值都是零,现在添加

一个引用计数,现在生成一个sp1对象,要调用构造函数对sp1进行初始化,将mptr传给地址域,mptr地址为0x100,通过

getRef()接口传递到引用计数管理器类中,要将0x100与地址域中的数据做比较,如查到与0x100相等的数据,则表明有智能指

针正在引用这个数据,对引用计数+1;如没查到就将0x100放到地址域中,放到新的节点去,引用计数加1就好了。

当sp1生存周期到后,应该先减引用计数,如果减为零就释放。

接口:

  • addRef():增加引用计数
  • delRef():   减引用计数
  • getRef():  获取引用计数

代码实现:

//引用计数管理器类
class RefManage
{
public:
  static RefManage* getInstance();
  {
  }
private:
  //初始化
  RefManage(): length(0)
  {}
  RefManage(const RefManage& rhs);
  
public:
  void addRef(void* ptr)
  {
     if(ptr != NULL)
     {
       int index = Find(mptr);
       if(index < 0)
       {
         /*
         arr[length].addr = ptr;
         arr[length].refcount++;
         */
      
         Node tmp(ptr ,1);
         arr[length++] = tmp;
       }
       else
       {
         arr[index].refcount++;
       }
     }
  }
  void delRef(void* ptr)
  {
     if(ptr != NULL)
     {
       int index = Find(ptr);
       if(index < 0)
       {
         throw exception("addr is not exist")
       }
       else
       {
         if(arr[index].refcount != 0)
         {
            arr[index].refcount--;
         }
       }
     }
  }
  int  getRef(void* ptr)
  {
     if(ptr != NULL)
     {
       return 0;
     }
     int index = Find(ptr);
     if(index < 0)
     { 
       return -1;
     }
     else
     {
      return arr[index].refcount;
     }
     
  }
  
private:
     //对内接口
     int Find(void * mptr)
     {
        for(int ℹ️= 0 ;ℹ️<length;++i)
        {
            if(arr[I].addr == ptr)
            {
               return ℹ️;
            }
        }
       return -1;
     }
     
     class Node
     {
      public:
           Node(void * ptr, int ref = 0)
           {
              addr = ptr;
              refcount = ref;
           }

           Node()
           {
               memset(this,0,sizeof(Node));
           }
      public:
           void* adds;
           int refcount;
     };

   //成员变量
   NOde arr[10];
   int length;//有效节点个数。当前要插入的节点下标
   static RefManage rm;
};

RefManage RefManage::rm;
//智能指针类
class Shared_ptr
{
public:
    Shared_ptr(T* ptr) :mptr(ptr)
    {
      AddRef();//调用引用计数管理器类中的addRef接口
    }
    

    Shared_ptr(const Share_ptr<T>& rhs):mptr(rhs.mptr)
    {
      AddRef();
    }
    
    Shared_ptr<T>& operator = (const Shared_ptr<T>& rhs)
    {
      if(this != &rhs)
      {
        if(GetRef() == 0)
        {
          delete mptr;
        }
        mptr = rhs.mptr;
        AddRef();
      }
      return *this;
    }
     
    ~Shared_ptr()
    {
      Delref();
      if(GetRef() == 0)
      {
        delete mptr;
      }
      mptr = NULL;
    }

    T* operator->()
    {
       return mptr;
    }

    T& operator*()
    {
       return *mptr;
    }

private:
    void AddRef()
    {
      rm->addRef(mptr);
    }
    
    void delRef()
    {
      rm->delRef(mptr);
    }
    
    int GetRef()
    {
      return rm->getRef(mptr);
    }
    T* mptr;
    static RefManage* rm;
};
//类外初始化
template<typename T>
RefManage* Shared_ptr<T>:: rm = RefManage::getInstance();

int main()
{
   int *p = new int;
   Shared_ptr<int> sp1(p);
   Shared_ptr<int> sp2(p);
   Shared_ptr<int> sp3(p);
   Shared_ptr<int> sp4(p);
   
   Shared_ptr<int> sp1(new int);
   Shared_ptr<int> sp2(sp1);
   return 0;
}

具体的分布:

1、创建shared_ptr实例

最安全和高效的方法是调用make_shared库函数,该函数会在堆中分配一个对象并初始化,最后返回指向此对象的share_ptr实例。如果你不想使用make_ptr,也可以先明确new出一个对象,然后把其原始指针传递给share_ptr的构造函数。

示例如下:

int main() {

    // 传递给make_shared函数的参数必须和shared_ptr所指向类型的某个构造函数相匹配
    shared_ptr<string> pStr = make_shared<string>(10, 'a');
    cout << *pStr << endl;  //  aaaaaaaaaa

    int *p = new int(5);
    shared_ptr<int> pInt(p);
    cout << *pInt << endl;  // 5
}

2、访问所指对象

shared_ptr的使用方式与普通指针的使用方式类似,既可以使用解引用操作符*获得原始对象进而访问其各个成员,也可以使用指针访问符->来访问原始对象的各个成员。

3、拷贝和赋值操作

我们可以用一个shared_ptr对象来初始化另一个share_ptr实例,该操作会增加其引用计数值。

例如:

int main() {
    shared_ptr<string> pStr = make_shared<string>(10, 'a');
    cout << pStr.use_count() << endl;  //  1

    shared_ptr<string> pStr2(pStr);
    cout << pStr.use_count() << endl;  //  2
    cout << pStr2.use_count() << endl;  //  2
}

如果shared_ptr实例p和另一个shared_ptr实例q所指向的类型相同或者可以相互转换,我们还可以进行诸如p = q这样赋值操作。该操作会递减p的引用计数值,递增q的引用计数值。

例如:

class Example
{
public:
    Example(string n) : name(n) { cout << n << " constructor..." << endl; }
    ~Example() { cout << name << " destructor..." << endl; }

    string name;
};

int main() {

    shared_ptr<Example> pStr = make_shared<Example>("a object");
    shared_ptr<Example> pStr2 = make_shared<Example>("b object");
    cout << pStr.use_count() << endl;
    cout << pStr2.use_count() << endl;

    pStr = pStr2;   // 此后pStr和pStr指向相同对象
    cout << pStr->name << endl;
    cout << pStr2->name << endl;
}


输出如下:

a object constructor...
b object constructor...

a object destructor...
b object
b object
b object destructor...

4、检查引用计数

shared_ptr提供了两个函数来检查其共享的引用计数值,分别是unique()和use_count()。

在前面,我们已经多次使用过use_count()函数,该函数返回当前指针的引用计数值。值得注意的是use_count()函数可能效率很低,应该只把它用于测试或调试。

unique()函数用来测试该shared_ptr是否是原始指针唯一拥有者,也就是use_count()的返回值为1时返回true,否则返回false。

示例:

int main() {
    shared_ptr<string> pStr = make_shared<string>(10, 'a');
    cout << pStr.unique() << endl;  // true

    shared_ptr<string> pStr2(pStr);
    cout << pStr2.unique() << endl; // false;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值