0
点赞
收藏
分享

微信扫一扫

[程序设计]引用计数的实现

引用计数的实现

  • reference_object.cc

总结

  • 引用计数可以减少对象的构造、析构的次数,一般用在一些开销比较大的对象上,或者需要对资源进行管理的对象上(比如套接字描述符被文件描述符)
  • 如果是POD类型或者简单类型,不要使用引用计数,反而会降低效率
  • 如果是要求线程安全的,则直接使用c++11提供的智能指针即可,除非是特别要求性能且不要求线程安全则可以实现自己的引用计数
  • 引用计数设计的时候,通过代理模式比侵入式的要好,使用方便,可以不用修改已有代码
  • 引用计数的线程安全指的是其计数的线程安全,而不是其所持有的对象的线程安全

引用计数类的设计

引用计数类最简单的形式就是在需要的类中增加一个计数器,以带有引用计数的字符串类为例:

class RfString
{
public:
  RfString(const char *s)
  {
    m_length = strlen(s);
    m_buf = new char[m_length + 1];
    memcpy(m_buf,s,m_length);
    m_refer_counter = new size_t;
    *m_refer_counter = 1;
  }

  RfString(const RfString &s):m_buf(s.m_buf),m_length(s.m_length)
  {
    m_refer_counter = s.m_refer_counter;
    *m_refer_counter++;
  }

  RfString(RfString &&s)
  {
    std::swap(m_buf,s.m_buf);
    std::swap(m_length,s.m_length);
    std::swap(m_refer_counter,s.m_refer_counter);
  }

  RfString &operator=(const RfString &s)
  {
    if (&s == this)
    {
      return *this;
    }
    m_buf = s.m_buf;
    m_length = s.m_length;

  }
private:
  

private:
  char *m_buf{nullptr};
  size_t m_length{0};
  size_t *m_refer_counter{nullptr};  // 引用计数
};

上面的代码虽然实现了字符串类的引用计数,但是却存在2个问题:

  • 代码是侵入式的,如果要在已有的类上使用引用计数功能,则必须修改当前的类,违背了设计模式中的开闭原则
  • 即使不考虑设计模式,效率上也有瑕疵,这里每次构造的时候都要拷贝3个成员变量,如果不是string类,而是一个含有成员较多的类呢?这些拷贝也会导致大量的构造函数的调用
  • 引用计数是否线程安全不可选

引用计数类的模板实现

// refer_counter.h
#include <string>
#include <atomic>
#include <iostream>
#include <string.h>

template <typename T,typename CounterType = std::atomic<size_t>>
class ReferrenceObject
{
public:
  ReferrenceObject(T *t):m_object(t)
  {
    m_refer_count = new CounterType;
    *m_refer_count = 1;
  }

  ~ReferrenceObject()
  {
    if (--(*m_refer_count) == 0)
    {
      delete m_object;
    }
  }

  ReferrenceObject(const ReferrenceObject &r):m_object(r.m_object),m_refer_count(r.m_refer_count)
  {
    (*m_refer_count)++;
  }

  ReferrenceObject(ReferrenceObject &&r)
  {
    std::swap(m_object,r.m_object);
    std::swap(m_refer_count,r.m_refer_count);
  }

  size_t refer_count() const
  {
    return *m_refer_count;
  }

  ReferrenceObject& operator=(const ReferrenceObject &r)
  {
    if (&r == this)
    {
      return *this;
    }

    if (--(*m_refer_count) == 0)
    {
      delete m_object;
    }
    
    m_object = r.m_object;
    m_refer_count = r.m_refer_count;
    (*m_refer_count)++;
    return *this;
  }

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

  const T &operator*() const
  {
    return *m_object;
  }

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

  const T *operator->() const
  {
    return m_object;
  }
private:
  T *m_object{nullptr};
  CounterType *m_refer_count{nullptr};
};

引用计数类的使用

#include "refer_counter.h"

class String
{
public:
  String(const char *s)
  {
    m_size = strlen(s);
    m_buf = new char[m_size + 1];
    memcpy(m_buf,s,m_size);
  }

  // 省略拷贝构造和拷贝赋值及优质拷贝构造

  friend std::ostream &operator<<(std::ostream &os,const String &s)
  {
    os << s.m_buf;
    return os;
  }

  ~String()
  {
    delete m_buf;
  }
private:
  char *m_buf{nullptr};
  size_t m_size{0};
};


using SafeRfString = ReferrenceObject<String,std::atomic<size_t>>;// 线程安全的引用计数
using RfString = ReferrenceObject<String,size_t>; // 非线程安全的引用计数

int main()
{
  RfString s(new String("hello world"));
  RfString a2(s);
  RfString a3(a2);
  RfString b1(new String("how are you?"));
  a2 = b1;

  std::cout << *s << ",refer counter = " << s.refer_count() << std::endl;
  std::cout << *b1 << ",refer counter = " << b1.refer_count() << std::endl;
  return 0;
}

// g++ -std=c++11 reference_object.cc
// output:
// hello world,refer counter = 2
// how are you?,refer counter = 2
举报

相关推荐

0 条评论