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="");//constructorString(const String& rhs);//copy constructorString& 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 pointervoid 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.

C++引用计数(reference counting)技术简介(2)相关推荐

  1. 提高C++性能的编程技术笔记:引用计数+测试代码

    引用计数(reference counting):基本思想是将销毁对象的职责从客户端代码转移到对象本身.对象跟踪记录自身当前被引用的数目,在引用计数达到零时自行销毁.换句话说,对象不再被使用时自行销毁 ...

  2. c++string 加引号_C++|引用计数与shared_ptr智能指针(以实现String类为例)

    C++ 中,动态内存的管理是通过一对运算符来完成的,new 用于申请内存空间,调用对象构造函数初始化对象并返回指向该对象的指针.delete接收一个动态对象的指针,调用对象的析构函数销毁对象,释放与之 ...

  3. C++ Primer 5th笔记(chap 13 拷贝控制)引用计数

    引用计数Reference Count 1. 问题 计数器存放在哪?作为类对象的成员时,遇到拷贝构造时如何处置? Hasptr p1("Hiya"); Hasptr p2(p1); ...

  4. C++引用计数(reference counting)技术简介(3)

    1.将Reference Counting加到既有的Class 要想将引用计数施加到现有的实值对象Widget上,按照前面讨论的,都需要修改Winget类的源代码.但是,有时程序库的内容不是我们呢可以 ...

  5. C++ 引用计数技术简介(1)

    1.引用计数的作用 C++ 引用计数(Reference Counting)是为弥补 C++ 没有垃圾回收机制而提出的内存管理的一个方法和技巧,它允许多个拥有共同值的对象共享同一个对象实体. 引用计数 ...

  6. 引用计数(Reference Counting)和代理(Proxy)的应用

    引子 如果让你用C++写一个实用的字符串类,我想下面的方案是很多人最先想到的: class ClxString { public: ClxString(); ClxString(const char ...

  7. Swift-自动引用计数(Automatic Reference Counting)(十四)

    前言 在iOS5之后apple推出了相对于MRC(Mannul Reference Counting)的ARC(Automatic Reference Counting)的内存管理机制,前者是对内存的 ...

  8. c++ reference counting引用计数原理

    我们都知道,c++最令人头疼的问题也是被其他语言鄙视的问题--指针管理.而引用技术能够让上面的简化了不少.下面说说c++引用计数的设计原理. 引用计数的两个动机: 1. 简化heap对象周边的记录工作 ...

  9. 【Netty4】netty ByteBuf (二) 引用计数对象(reference counted objects)

    原文出处:http://netty.io/wiki/reference-counted-objects.html 相关文章: netty ByteBuf (一)如何创建ByteBuf对象 netty ...

最新文章

  1. jquery的文档处理(部分)
  2. 判断某个点是否在不规则图形内
  3. oracle 数据库讲解,oracle数据库基本讲解(菜鸟篇)
  4. Python语言学习:解决python版本升级问题集合(python2系列→Python3系列)导致错误的总结集合
  5. 云主机初体验(盛大云和阿里云)
  6. What is the usage of getMasterKeyAttributes in configuration.js
  7. POJ 2967 (水题,考察putchar()按位输入)
  8. 简单易用的开源ORM框架SqlSugar v5.0.0.19源码
  9. 妈咪,我找到了!15个实用的Linux find命令示例
  10. Linux之特殊的环境变量IFS以及如何删除带有空格的目录
  11. 观察者模式代码php,PHP 观察者模式的实现代码
  12. [JNI] 开发之旅 (2)解释jni helloworld实例
  13. magisk下载里显示没有模块_太极Magisk模块
  14. 小程序JSAPI预下单与回调
  15. 项目配置管理CM(Configuration Management)
  16. worldpress自定义页面
  17. 使用canvas绘制一个三角形
  18. aws s3 参与s3game寻找宝藏游戏挑战学习s3对象存储
  19. 关于JS下offsetLeft,style.left,以及jquery中的offset().left,css(left)的区别。
  20. python进阶之路———文件处理

热门文章

  1. 动态生成圈形+文字的图片
  2. 寒假训练营第四次作业
  3. Activiti 工作流变量的修改方法
  4. NLPIR语义智能平台支持大数据个性化学习
  5. 用Aliyun E-MapReduce集群的sqoop工具和数据库同步数据如何配置网络
  6. juniper srx 3400 双机 配置
  7. C#从新浪新闻上提取新闻标题
  8. Linux下DNS服务管理
  9. javascript的拖放(第1部分)
  10. mongodb db.serverStatus() 仍然不能提示认证失败