C++ 拷贝控制和资源管理,智能指针的简单实现

C++ 关于拷贝控制和资源管理部分的笔记,并且介绍了部分C++ 智能指针的概念,然后实现了一个基于引用计数的智能指针。关于C++智能指针部分,后面会有专门的研究。

  • 通常,管理类外资源的类必须定义拷贝控制成员。为了定义这些成员,我们首先必须确定此对象的拷贝语义。一般来讲,有两种选择:
    • 使类的行为看起来像一个值

        类的行为像一个值:意味着它有自己的状态。当我们拷贝一个像值的对象时,副本和原对象是完全对立的。改变副本不会对对原对象有任何影响。反之亦然。
    • 使类的行为看起来像一个指针

        行为像指针的类则共享状态。当我们拷贝一个这种类的对象时,副本和原对象使用相同的底层数据。改变副本也会改变原对象,反之亦然。
  • 行为像值的类
    • 为了提供类值的行为,对于类管理的资源,每个对象应该都拥有一份自己的拷贝。
    • 类值拷贝赋值运算符
      • 通常组合了析构函数和构造函数的操作。类似析构函数,赋值操作会销毁左侧运算对象的资源。类似构造函数,赋值操作会从右侧运算对象拷贝数据。
      • 编写赋值运算符时,有两点需要注意:

          1. 如果将一个对象赋予它自身,赋值运算符必须能正确工作
          2. 大多数赋值运算符组合了析构函数和拷贝构造函数的工作
      • 当编写一个赋值运算符时,一个好的方法是先将右侧运算对象拷贝到一个局部临时对象中,然后再销毁左侧运算对象就是安全的了。

  • 定义行为像指针的类
    • 引用计数

        引用计数的工作方式如下:
        1. 除了初始化对象之外,每个构造函数(拷贝构造函数除外)还要创建一个引用计数,用来记录有多少对象正在与创建的对象共享状态。当我们创建一个对象时,只有一个对象共享状态,因此计数器初始化为1。
        2. 拷贝构造函数不分配新的计数器,而是拷贝给定对象的数据成员,包括计数器。拷贝构造函数递增共享的计数器,指出给定对象的状态又被一个新用户共享。
        3. 析构函数递减计数器,指出共享状态的用户少了一个。如果计数器变为0,则析构函数释放状态。
        4. 拷贝赋值运算符递增右侧运算对象的计数器,递减左侧运算对象的计数器。如果左侧运算对象的计数器变为0,意味着它的共享状态没有用户了,拷贝赋值运算符就必须销毁状态。
    • 引用计数的存放位置:一种方法只保存在动态内存中。当创建一个对象时,我们也分配一个计数器。当拷贝或赋值对象时,我们拷贝指向计时器的指针。使用这种方法,副本和原对象都会指向相同的计数器。

  • 下面给出一个基于引用计数的共享智能指针的实现。
    ```cpp
    #include
    using namespace std;

    template
    class SmartPtr{
    public:
    //构造函数
    SmartPtr(T *sp = NULL)
    :m_ptr(sp), use_count(new std::size_t(1)){}

      //拷贝构造函数
      SmartPtr(const SmartPtr<T> &ref){
          if (this != &ref){
              m_ptr = ref.m_ptr;
              use_count = ref.use_count;
              ++*use_count;
          }
      }
    
      //拷贝赋值运算符
      SmartPtr& operator=(const SmartPtr<T> &ref){
          if (this == &ref)   //处理自赋值情况
              return *this;
    
          //判断原use_count是否为0
          --*use_count;
          if (*use_count == 0){
              delete m_ptr;
              delete use_count;
              m_ptr = NULL;
              use_count = NULL;
              cout << "operator= delete" << endl;
          }
    
          m_ptr = ref.m_ptr;
          use_count = ref.use_count;
          ++*use_count;
      }
    
      //析构函数
      ~SmartPtr(){
          --*use_count; 
          if (*use_count == 0){
              delete m_ptr;
              delete use_count;
              m_ptr = NULL;
              use_count = NULL;
              cout << "~SmartPtr()  and delete" << endl;
          }
          else
              cout << "~SmartPtr()  use_count:" << *use_count <<endl;
      }
    
      T * get(){
          return m_ptr;
      }
    
      std::size_t getUse_count(){
          return *use_count;
      }

    private:
    //基础对象指针
    T m_ptr;
    std::size_t
    use_count;
    };

    class Test{
    public:
    Test(int a, char b) :_a(a), _b(b){}
    void print(){
    cout << _a << " " << _b << " ";
    }
    private:
    int _a;
    char _b;
    };

    int main(){
    //内置数据类型测试
    cout << "内置数据类型测试" << endl;
    SmartPtr sp1(new int(5)); //默认构造函数
    cout << *sp1.get() << " " << sp1.getUse_count() << endl;

      SmartPtr<int> sp2(sp1);  //拷贝构造函数
      cout << *sp2.get() << "  " << sp2.getUse_count() << endl;
    
      SmartPtr<int> sp3;
      sp3 = sp1;          //拷贝赋值运算符
      cout << *sp3.get() << "  " << sp3.getUse_count() << endl;
    
      sp3 = sp3;    //自赋值情况
      cout << *sp3.get() << "  " << sp3.getUse_count() << endl;
    
      //自定义数据类型测试
      cout << endl << endl << "自定义数据类型测试" << endl;
      SmartPtr<Test> tp1(new Test(10, 'c'));  //默认构造函数
      (tp1.get())->print();
      cout << tp1.getUse_count() << endl;
    
      SmartPtr<Test> tp2(tp1);   //拷贝构造函数
      (tp2.get())->print();
      cout << tp2.getUse_count() << endl;
    
      SmartPtr<Test> tp3;      
      tp3 = tp1;              //拷贝赋值运算符
      (tp3.get())->print();
      cout << tp3.getUse_count() << endl;
    
      tp3 = tp3;   //自赋值情况
      (tp3.get())->print();
      cout << tp3.getUse_count() << endl;
    
      cout << endl << endl <<  "析构函数" << endl;
      return 0; 

    }
    ```

  • 程序运行结果如下:
    1122912-20170402120659633-1250973792.png

转载于:https://www.cnblogs.com/lengender-12/p/6658679.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值