关于c++智能指针的引用计数原理

        使用过智能指针的朋友都知道,有些智能指针是通过引用计数来实现的,那引用计数到底是什么呢,他是如何实现?下面我们就来详细讲解

        引用计数是一种内存管理技术。我们以下面自定义的String类为例:

class String {
 public:
  ~String() { if (val_) { delete[] val_; }}
  String(const char* val) : String(val, val ? strlen(val) : 0) {}
  String(const String& str) { 
    /*引用计数*/
  }
  String& operator=(const String& str) { 
    /*引用计数*/
    return *this;
  }
  String(const char* val, int len) {
    if (val && len > 0) {
      val_ = new char[len + 1]();
      std::copy_n(val, len, val_);
    }
  }

 private:
  char* val_ = nullptr;
};

我们思考一下,如何才能在拷贝构造和赋值运算的时候给val_添加引用计数,如下场景:

String a{"i am ref is one"}, c
String b(a)
c = b

我们知道a、b、c三个对象虽然是不同的String实例,但是他们属于同一个进程,可以共享堆内存或者说自由存储区,所以想要给val_添加引用计数,那么这个计数就需要放到堆空间,所以我们将val_进行如下改造:

struct StringValue {
    int ref;
    char* val;
    StringValue(const char* v, int len): ref(0), val(nullptr) {
      if (v && len > 0) {
        val = new char[len + 1]();
        std::copy_n(v, len, val);
      }
    }
    ~StringValue() { delete[] val; }
  };
  StringValue* val_ = nullptr;

我们可以看到val_类型被修改为StringValue,原来的char*被放到了StringValue结构体里,并添加了ref变量用来计数, 此时如果a、b、c三个val_相同,那么他们指向的val_->ref也是相同的,所以我们需要做点改动让a、b、c指向同一个val_

class String {
 public:
  ~String() {
    // 引用计数为0
    if (val_ && --val_->ref) {
      delete val_;
    }
  }
  String(const char* val) : String(val, val ? strlen(val) : 0) {}
  String(const char* val, int len) { val_ = new StringValue(val, len); }
  String(const String& str) { 
    /*引用计数*/
    this->val_ = str.val_;  // 指向同一个val_
    ++(this->val_->ref); // 引用计数 +1
  }
  String& operator=(const String& str) { 
    /*引用计数*/
    this->val_ = str.val_;  // 指向同一个val_
    ++(this->val_->ref);    // 引用计数 +1
    return *this;
  }

 private:
  struct StringValue {
    int ref;
    char* val;
    StringValue(const char* v, int len): ref(0), val(nullptr) {
      if (v && len > 0) {
        val = new char[len + 1]();
        std::copy_n(v, len, val);
      }
    }
    ~StringValue() { delete[] val; }
  };
  StringValue* val_ = nullptr;
};

我们可以看到,在拷贝构造和赋值操作的时候可以将其指向同一个堆内存。并且引用计数加一,当a、b、c对象析构的时候对引用计数减一,以此来达到对val的引用计数。

        关于引用计数的计数原理已经讲完了,大家可以思考一个问题,为什么是对val进行引用计数,而不是使用static对class进行引用计数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值