智能指针(smart point) unique_ptr,shared_ptr 详解,代码实现

资源管理RAII

RAII是C++之父Bjarne Stroustrup提出的概念,RAII全称是“Resource Acquisition is Initialization”,即 “资源请求即初始化”, 为解决资源管理时异常安全性所使用的资源管理方法。 RAII要求资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配,同时由析构函数完成资源的释放。

使用 C++ 申请的堆内存空间, 需要程序员自己负责管理回收。然而在编程时稍有不小心会很容易造成内存泄漏。smart point 就是 RAII 资源管理方式,通常是用类模板实现,借用类的析构函数来达成自动释放类中指针所指向的内存空间和对象。智能指针有auto_ptr(C++17 已经被正式从C++标准里删除了)、unique_ptr、shared_ptr。

unique_ptr(since c++11)

代码:

///
 /// @file    unique_ptr.cc
 /// @author  yll(1711019653@qq.com)
 /// @date    2021-06-03 14:05:33
 ///
 
#include <iostream>
#include <algorithm>
#include <memory>
using std::cout;
using std::endl;
​
//数组类的指针使用的unique_ptr模板的特化版
/**
 *
 /// unique_ptr for array objects 
template<typename _Tp, typename _Dp>
class unique_ptr<_Tp[], _Dp>
{
        ...  
}
 */
template<typename T, typename D = std::default_delete<T> >
class unique_ptr
{
​
public:
​
  unique_ptr()
  :_ptr(nullptr)
  {
    cout << "construct unique ptr null" << endl;
  }
​
  unique_ptr(T* ptr)
  :_ptr(ptr)
  {
    cout << "construct unique ptr" << endl;
  }
  
  //c++ 11, 利用移动语义,可以将指针使用权进行转移 
  unique_ptr(unique_ptr&& other)
  {
    _ptr = other.release();
  }
​
  unique_ptr& operator=(unique_ptr&& other)
  {
    _ptr = other.release();
    return *this;
  }
  
  T& operator*()
  {
    return *_ptr;
  }
​
  T* operator->()
  {
    return _ptr;
  }
  
  T* release()
  {
    T* ptr = _ptr;
    _ptr = nullptr;
    return ptr;
  }
​
  //对外屏蔽复制构造函数和赋值构造函数
  //方法一 删除 复制构造函数和赋值构造函数
  //unique_ptr(const unique_ptr<T> & ptr) = delete;
  //unique_ptr(const unique_ptr<T, D> & ptr) = delete;
​
  //unique_ptr& operator=(const unique_ptr<T, D>& ptr) = delete;
  
  ~unique_ptr()
  {
    _deleter(_ptr);
  }
  
  void swap( unique_ptr& other)
  {
    std::swap(_ptr, other._ptr);
  }
​
protected:
  
  //方法二 注册复制构造函数和赋值构造函数为protected,对外屏蔽
  unique_ptr(const unique_ptr<T, D> & ptr)
  {
  }
  unique_ptr& operator=(const unique_ptr<T, D>& ptr)
  {}
​
private:
  T * _ptr;
  D _deleter; 
};

测试代码:

class Test
{
public:
  Test()
  {
    cout << "test" << endl;
  }
  
  void Print()
  {
    cout << "Print Test " << endl;
  }
​
  ~Test()
  {
    cout << "~test" << endl;
  }
};
​
template <class T>
struct deleter
{
  void operator()(T* ptr) const 
  {
    if(ptr)
    {
      cout << "deleter " << endl;
      delete ptr;
    }
  }
};
​
int main(void)
{
  using unique_test = ::unique_ptr<Test, deleter<Test> >;
  unique_test uPtr(new Test());
  uPtr->Print();
  //unique_ptr<Test> uPtr2(uPtr);
  //uPtr2->Print();
  //unique_test uPtr3 = uPtr;
  unique_ptr<Test> uPtr4(std::move(uPtr));
  return 0;
}

运行结果:

如果将注释部分取消,会出现报错,无法对 unique_ptr 进行复制: 

shared_ptr:

        unique_ptr 算是一种较为安全的智能指针了。但是,一个对象只能被单个 unique_ptr 所拥有,这显然不能满足所有使用场合的需求。一种常见的情况是,多个智能指针同时拥有一个对象;当它们全部都失效时,这个对象也同时会被删除。这也就是 shared_ptr 了。

        多个不同的 shared_ptr 不仅可以共享一个对象,在共享同一对象时也需要同时共享同一个计数。

代码:

template<class T, class D = std::default_delete<T> >
class shared_ptr
{
public:
  shared_ptr()
  :_ptr(nullptr)
  ,_uCount(nullptr)
  {
    cout << "default constructor " << endl;
  }
​
  shared_ptr(T* ptr)
  :_ptr(ptr)
  ,_uCount(new size_t(1))
  {
    cout << " constructor T*" << endl;
  } 
  
  shared_ptr(T* ptr, D deleter)
  :_ptr(ptr)
  ,_deleter(deleter)
  ,_uCount(new size_t(1))
  {
    cout << " constructor T* DD " << endl;
  }
​
  shared_ptr(const shared_ptr<T, D> & sharedPtr)
  {
    if(sharedPtr._ptr)
    {
      _ptr = sharedPtr._ptr;
      _uCount = sharedPtr._uCount;
      add_count();
    }
  }
  
  shared_ptr& operator=(const shared_ptr<T, D> & sharedPtr)
  {
    if(_ptr == sharedPtr._ptr){ return *this; }
    
    //为了释放之前管理的旧资源
    if(*_uCount == 1){  
      free(); 
    }else{
      reduce_count();
    }
​
    _ptr = sharedPtr._ptr;
    _uCount = sharedPtr._uCount;
    add_count();
​
    return *this;
  }
  
  void swap(shared_ptr<T, D> & sharedPtr)
  {
    std::swap(_ptr, sharedPtr._ptr);
    std::swap(_uCount, sharedPtr._uCount);
  }
​
  void reset(T* ptr)
  {
    if(*_uCount == 1){ 
      free(); 
    }else{
      reduce_count();   
    }
​
    _ptr = ptr;
    _uCount = new size_t(1);
  }
​
  T* get() const  { return _ptr; }
​
  size_t use_count()const { return *_uCount; }
​
  void print_use_count()
  {
    cout << *_uCount << endl;
  }
  ~shared_ptr()
  {
    //Call Deleter 
    if(*_uCount == 1){
      free();
    }else{
      reduce_count();
      print_use_count();
    }
  }
private:
​
  void reduce_count()
  {
    if(*_uCount > 0) -- ( *_uCount);
  }
  
  void add_count()  { ++(*_uCount); }
  
  void free()
  {
    _deleter(_ptr);
    delete _uCount;
  }
private:
​
  T* _ptr;
  //std::function<void(T*)> _deleter;
  D _deleter;
  size_t* _uCount ; 
};

测试代码:

class Test
{
public:
  Test()
  {
    cout << "test" << endl;
  }
  
  void Print()
  {
    cout << "Print Test " << endl;
  }
​
  ~Test()
  {
    cout << "~test" << endl;
  }
};
​
template <class T>
struct deleter
{
  void operator()(T* ptr) const 
  {
    if(ptr)
    {
      cout << "deleter " << endl;
      delete ptr;
    }
  }
};
​
int main(void)
{ 
  shared_ptr<Test, deleter<Test>> ptr1(new Test());
  ptr1.print_use_count();
​
  shared_ptr<Test, deleter<Test>> ptr2(ptr1); 
  ptr1.print_use_count();
  
  shared_ptr<Test, deleter<Test>> ptr3 = ptr1; 
  ptr1.print_use_count();
  return 0; 
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值