C++引用计数(reference counting)技术简介(2)

来源:互联网 发布:塞班软件下载5233 编辑:程序博客网 时间:2024/06/05 19:34

1.一个引用计数(Reference-Counting)基类

Reference-counting可用于字符串以外的场合,任何class如果其不同的对象可能拥有相同的值,都适用此技术。但是如果重写class以便适用reference counting可能需要大量的工作。

我们可以设计一个引用计数基类RCObject,供想拥有引用计数的类继承。RCObject将“引用计数器”本身以及用以增减引用数值的函数封装起来。此外,还包括销毁对象值的函数,设置不可共享标的函数,返回共享标志的函数,查询是否在被共享的函数,查询引用计数的数目。没有必要提供一个设定共享标志位true的成员函数,因为所有的对象值在默认情况下都是可共享的。这里设定一旦某个对象被贴上”不可共享”标签,其永远都将是不可共享。

RCObject定义如下:

//引用计数基类  class RCObject{  public:      RCObject();//构造函数      RCObject(const RCObject& rhs);//拷贝构造函数      RCObject& operator=(const RCObject& rhs);//拷贝赋值运算符      virtual ~RCObject() = 0;//析构函数    void addReference();//增加引用计数      void removeReference();//减少引用计数,如果变为0,销毁对象      void markUnshareable();//将可共享标志设为false      bool isShareable() const;//判断其值是否可共享      bool isShared() const;//判断其值是否正在被共享      int getRefCount();//返回引用计数    private:      int refCount;//保存引用计数      bool shareable;//保存其值是否可共享的状态  };  //构造函数,这里refCount设为0,让对象创建者自行或将refCoun设为1  RCObject::RCObject(void) :refCount(0), shareable(true){}  //拷贝构造函数,总是将refCount设为0,因为正在产生一个新对象,只被创建者引用  RCObject::RCObject(const RCObject&) : refCount(0), shareable(true){}  //拷贝赋值运算符,这里只返回*this,因为左右两方RCObject对象的外围对象个数不受影响  RCObject& RCObject::operator=(const RCObject& rhs){      return *this;  }  //析构函数  RCObject::~RCObject(){}  //增加引用计数  void RCObject::addReference(){      ++refCount;  }  //减少引用计数,如果变为0,销毁对象  void RCObject::removeReference(){      if (--refCount == 0)          delete this;  }  //将追踪其值是否可共享的成员设为false  void RCObject::markUnshareable(){      shareable = false;  }  //判断其值是否可共享  bool RCObject::isShareable() const{      return shareable;  } //判断其值是否正在被共享  bool RCObject::isShared() const{      return refCount>1;  }  //返回引用计数  int RCObject::getRefCount(){      return refCount;  }  

注意:
(1)RCObject的赋值运算符opeator=()什么也没有做,实际上可共享的实值实际不太可能被赋值。例如在自定义String类中,实值StringValue并不不会被赋值,而是String对象的赋值。

(2)RCObject::removeReference的责任不只在于将对象的refCount递减,而有当引用计数refCount为0时,销毁实值对象。使用delete this来销毁实值对象,那就要求*this是heap对象。

2.基于引用计数基类的String

基于引用计数的基类String设计如下:

class String{private:    Struct StringValue:public RCObject{        char* data;        StringValue(const char* initValue);        ~StringValue();    };    StringValue* value;  public:    String(const char* initValue="");//constructor    String(const String& rhs);//copy constructor    String& operator=(const String& rhs); //assignment operator    ~String(); //destructor};//StringValue的构造函数String::StringValue::StringValue(const char* initValue):refCount(1){     data=new char[strlen(initValue)+1];     strcpy(data,initValue); }//StringValue的析构函数String::StringValue::~StringValue(){    delete[] data;}

这一版本的StringValue几乎与前一版本完全相同,唯一的改变是StringValue的member functions不再处理引用计数refCount字段,改由RCObject掌握。

3.自动操作引用次数(Reference Count)

RCObject class存放了引用次数,也给出了操作引用次数的member fucntions,这些函数的调用动作还是得用户手动写到其他的class内,并且通过String constructor和String assignment operator调用StringValue对象所提供的addReference和removeReference。这里,我们使用可复用的类,不必让用户类去操作引用次数。这里可复用的类产生的对象我们呢称之为smart pointer。

下面使用template来实现smart pointers,指向reference-counted实值对象。

//智能指针模板类,用来自动执行引用计数实值类成员的操控动作  template<typename T>                        class RCPtr{                           public:                   RCPtr(T* realPtr = 0);//构造函数      RCPtr(const RCPtr& rhs);//拷贝构造函数      ~RCPtr();//析构函数      RCPtr& operator=(const RCPtr& rhs);//拷贝赋值运算符      T* operator->() const;//重载->运算符      T& operator*() const;//重载*运算符  private:      T* pointee;  //dumb pointer    void init(); //共同的初始化操作  };  //共同的初始化操作  template<typename T>  void RCPtr<T>::init(){      if (pointee == 0) return;      if (pointee->isShareable() == false) {          pointee = new T(*pointee);      }      pointee->addReference();  }  //构造函数  template<typename T>  RCPtr<T>::RCPtr(T* realPtr) :pointee(realPtr){      init();  }  //拷贝构造函数  template<typename T>  RCPtr<T>::RCPtr(const RCPtr& rhs) : pointee(rhs.pointee){      init();  }  //析构函数  template<typename T>  RCPtr<T>::~RCPtr(){      if (pointee)          pointee->removeReference();  }  //赋值运算符  template<typename T>  RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs){      if (pointee != rhs.pointee) {          if (pointee)              pointee->removeReference();          pointee = rhs.pointee;          init();      }      return *this;  }  //重载成员选取运算符 -> template<typename T>  T* RCPtr<T>::operator->() const { return pointee; }  //重载解引用运算符*  template<typename T>  T& RCPtr<T>::operator*() const { return *pointee; }  

4.最终String

在上面的基础之上,我们利用具有服用性质的RCObject和RCPtr classes为基础,建造一个reference-counted String class。每一个具有引用计数功能的String对象均以此数据结构实现出来:
这里写图片描述

最终的String描述如下:

class String {                             public:                                      String(const char *value = "");//构造函数      const char& operator[](int index) const;//重载[]运算符,针对const Strings      char& operator[](int index);//重载[]运算符,针对non-const Strings  private:      struct StringValue : public RCObject {//继承自引用计数基类          char *data;          StringValue(const char *initValue);//构造函数          StringValue(const StringValue& rhs);//拷贝赋值运算符          void init(const char *initValue);          ~StringValue();//析构函数      };      RCPtr<StringValue> value;//智能指针对象  };  //String::StringValue实现代码  void String::StringValue::init(const char *initValue){      data = new char[strlen(initValue) + 1];      strcpy(data, initValue);  }  //StringValue类的构造函数  String::StringValue::StringValue(const char *initValue){      init(initValue);  }  //StringValue类的拷贝赋值运算符  String::StringValue::StringValue(const StringValue& rhs){      init(rhs.data);  }  //StringValue类的析构函数  String::StringValue::~StringValue(){      delete[] data;  }  //String实现代码  //String类的构造函数  String::String(const char *initValue): value(new StringValue(initValue)) {}  //重载[]运算符,针对const Strings  const char& String::operator[](int index) const{      return value->data[index];  }  //重载[]运算符,针对non-const Strings  char& String::operator[](int index){      if (value->isShared()) {          value = new StringValue(value->data);      }      value->markUnshareable();      return value->data[index];  }  

注意,这里使用智能指针对象的String并不需要显示定义copy constructor和assignment operator,因为这些编译器为默认生成,并且会自动调用String内RCPtr member的copy constructor和assignment operator,而后者又会自动执行对StringValue对象的所有处理,包括引用次数。


[1]More Effective C++.Scott Meyers著,侯捷译.P183-213.
[2]http://blog.csdn.net/ruan875417/article/details/48267527.

1 0
原创粉丝点击