C++引用计数(reference counting)技术简介(2)
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)相关推荐
- 提高C++性能的编程技术笔记:引用计数+测试代码
引用计数(reference counting):基本思想是将销毁对象的职责从客户端代码转移到对象本身.对象跟踪记录自身当前被引用的数目,在引用计数达到零时自行销毁.换句话说,对象不再被使用时自行销毁 ...
- c++string 加引号_C++|引用计数与shared_ptr智能指针(以实现String类为例)
C++ 中,动态内存的管理是通过一对运算符来完成的,new 用于申请内存空间,调用对象构造函数初始化对象并返回指向该对象的指针.delete接收一个动态对象的指针,调用对象的析构函数销毁对象,释放与之 ...
- C++ Primer 5th笔记(chap 13 拷贝控制)引用计数
引用计数Reference Count 1. 问题 计数器存放在哪?作为类对象的成员时,遇到拷贝构造时如何处置? Hasptr p1("Hiya"); Hasptr p2(p1); ...
- C++引用计数(reference counting)技术简介(3)
1.将Reference Counting加到既有的Class 要想将引用计数施加到现有的实值对象Widget上,按照前面讨论的,都需要修改Winget类的源代码.但是,有时程序库的内容不是我们呢可以 ...
- C++ 引用计数技术简介(1)
1.引用计数的作用 C++ 引用计数(Reference Counting)是为弥补 C++ 没有垃圾回收机制而提出的内存管理的一个方法和技巧,它允许多个拥有共同值的对象共享同一个对象实体. 引用计数 ...
- 引用计数(Reference Counting)和代理(Proxy)的应用
引子 如果让你用C++写一个实用的字符串类,我想下面的方案是很多人最先想到的: class ClxString { public: ClxString(); ClxString(const char ...
- Swift-自动引用计数(Automatic Reference Counting)(十四)
前言 在iOS5之后apple推出了相对于MRC(Mannul Reference Counting)的ARC(Automatic Reference Counting)的内存管理机制,前者是对内存的 ...
- c++ reference counting引用计数原理
我们都知道,c++最令人头疼的问题也是被其他语言鄙视的问题--指针管理.而引用技术能够让上面的简化了不少.下面说说c++引用计数的设计原理. 引用计数的两个动机: 1. 简化heap对象周边的记录工作 ...
- 【Netty4】netty ByteBuf (二) 引用计数对象(reference counted objects)
原文出处:http://netty.io/wiki/reference-counted-objects.html 相关文章: netty ByteBuf (一)如何创建ByteBuf对象 netty ...
最新文章
- jquery的文档处理(部分)
- 判断某个点是否在不规则图形内
- oracle 数据库讲解,oracle数据库基本讲解(菜鸟篇)
- Python语言学习:解决python版本升级问题集合(python2系列→Python3系列)导致错误的总结集合
- 云主机初体验(盛大云和阿里云)
- What is the usage of getMasterKeyAttributes in configuration.js
- POJ 2967 (水题,考察putchar()按位输入)
- 简单易用的开源ORM框架SqlSugar v5.0.0.19源码
- 妈咪,我找到了!15个实用的Linux find命令示例
- Linux之特殊的环境变量IFS以及如何删除带有空格的目录
- 观察者模式代码php,PHP 观察者模式的实现代码
- [JNI] 开发之旅 (2)解释jni helloworld实例
- magisk下载里显示没有模块_太极Magisk模块
- 小程序JSAPI预下单与回调
- 项目配置管理CM(Configuration Management)
- worldpress自定义页面
- 使用canvas绘制一个三角形
- aws s3 参与s3game寻找宝藏游戏挑战学习s3对象存储
- 关于JS下offsetLeft,style.left,以及jquery中的offset().left,css(left)的区别。
- python进阶之路———文件处理