概念:
允许多个等值对象共享同一个实值。
目的:
1).一旦某个对象new分配,记录对象拥有者很重要,并且负责有删除对象,但是执行过程中对象拥有权可能转移。
引用计数可以消除对象拥有权负荷,建立出垃圾回收机制
2).如果多个对象相同的值,那么还进行多次存储浪费内存。
class String {
public:
String(const char *value = "");
String& operator=(const String& rhs);
... private:
char *data;
};
String a, b, c, d, e;
a = b =c =d=e= "hello";
五个对象将分别拥有自己的一份数据累赘与浪费
引用计数的实现
是为了每个值准备的引用次数而不是对象准备的应该有耦合关系
class String{
public:
String(const char*initValue="");
String(const String&rhs);
<span style="white-space:pre"> </span>String&operator=(const String&rhs);
<span style="white-space:pre"> </span>~String();
private:
struct StringValue{
int refCount;
char *data;
StringValue(const char*initValue);
~StringValue();
};
StringValue *value;
};
//初始化的时候第一次引用次数为1
String::StringValue::StringValue(const char*initValue):refCount(1){
data = new char[strlen(initValue)+1];
strcpy(data,initValue);
}
String::StringValue::~StringValue(){
delete[]data;
}
//构造函数尽可能简单
String::String(const char*initValue):value(new StringValue(initValue))
{
}
String::String(const String&rhs):value(rhs.value){
++value->refCount;
}
String s1("More Effective C++");
String s2 = s1;
String s2 = s1;
会导致这样的数据结构
比传统的没有引用计数的效率高,因为不需要分配内存给字符串的第二个副本
//析构函数的实现
//引用次数不是0那么至少有一个string 对象正字啊使用这个值
String::~String(){
if (--value->refCount==0)
delete value;
}
//引用次数不是0那么至少有一个string 对象正字啊使用这个值
String::~String(){
if (--value->refCount==0)
delete value;
}
//赋值操作是s1和s2同时指向一个对象引用次数加1
String& String::operator=(const String&rhs){
if (value==rhs.value)//数值相同什么也不做
return *this;
if (--value->refCount==0)//没有其他人使用那么销毁
{
delete value;
}
value = rhs.value;//*this共享rhs的数值
++value->refCount;
return *this;
}
String& String::operator=(const String&rhs){
if (value==rhs.value)//数值相同什么也不做
return *this;
if (--value->refCount==0)//没有其他人使用那么销毁
{
delete value;
}
value = rhs.value;//*this共享rhs的数值
++value->refCount;
return *this;
}
写时才复制(copy-on-write)
String s;
cout<<s[3];//读操作
s[5] = 'x';//写动作
我们希望读写动作的处理是不一样的 必须避免更动共享同一个stringvalue对象的其他string
但我们无法知道operator[]是用于读还是写所以只有假设non-const operator[]就是写操作
//只读动作字符串内容不做修改
const char& String::operator[](int index)const{
return value->data[index];
}
char& String::operator[](int index){
//如果本对象和其他对象共享同一个值
//就分割出另一个副本给自己使用
if (value->refCount>1)
{
--value->refCount;
value = new StringValue(value->data);//为自己做一个新的副本
}
return value->data[index];
}
该技术运用广泛特别是操作系统,进程之间往往共享某些内存分页,直到他们打算修改内存分页的时候这项技术缓释评估,提升效率的方法。
指针,引用以及写时复制
String s1 = "HELLO";
char*p = &s1[1];
String s2 = s1;
*p = 'x';//同时修改s1和s2
方法是:一开始树立独享被共享的标志,一段operator[]作用对象的值那么标志立即清除。会降低对象之间的共享的实值的个数
class String{
private:
struct StringValue{
int refCount;
bool shareable;
char*data;
StringValue(const char*initvalve);
~StringValue();
};
};
String::StringValue::StringValue(const char*initValue):refCount(1),shareable(true)
{
data = new char[strlen(initValue)+1];
strcpy(data,initValue);
}
String::StringValue::~StringValue()
{
delete[]data;
}
char &String::operator[](int index)
{
if (value->refCount>1)
{
--value->refCount;
value = new StringValue(value->data);
}
value->shareable = false;
return value->data[index];
}
撰写引用计数的基类
任何其他不同对象可能拥有相同值,可以在外界无关联的环境下撰写引用计数的代码,然后必要的时候移植到class
class RCObject{
public:
RCObject();
RCObject(const RCObject&rhs);
RCObject&operator=(const RCObject&rhs);
virtual ~RCObject()=0;
void addReference();
void removeReference();
void markUnShareable();
bool isShareable()const;
bool isShared()const;
private:
int refCount;
bool shareable;
};
RCObjects可以被赋予更高的引用次数,也可以移除目前的引用次数,共享状态可以被查询
refCount的创建者有义务为refCount设定适当的值
一定要搞清楚是对值的引用而不是对对象的引用
class String
{
private:
struct StringValue:public RCObject{
char *data;
StringValue(const char*initValue);
~StringValue();
};
};
String::StringValue::StringValue(const char*initValue)
{
data = new char[strlen(initValue) + 1];
strcpy(data,initValue);
}
String::StringValue::~StringValue()
{
delete[]data;
}
stringvalue的成员函数不再处理refCount而又RCObject掌管
自动操作引用次数
上面的调用还是需要用String的复制构造函数,和赋值函数调用stringvalue然后进行对引用次数的修改
我们希望这些调用在一个可以复用的class类中这样让比如string类的class能够不必担心引用计数的实现细节
实现思路:如果能够让指针本身侦测到自动执行refCount成员的操控。
我们用智能指针管理对象让自动执行处理工作。
template<class 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;
void init();
};
template<class T>
RCPtr<T>::RCPtr(T*realPtr):pointee(realPtr)
{
init();
}
template<class T>
RCPtr<T>::RCPtr(const RCPtr&rhs):pointee(rhs.pointee)
{
init();
}
template<class T>
void RCPtr<T>::init()
{
if (pointee==0)
return;
if (pointee->isShareable()==false)
{
pointee = new T(*pointee);
}
pointee->addreference();
}
内含指针的类应该重写copy构造函数因为这正是指针悬挂等问题根源
template<class T>
RCPtr<T>::~RCPtr()
{
if (pointee)
pointee->removeReference();
}
template<class T>
RCPtr<T>&RCPtr<T>::operator=(const RCPtr&rhs)
{
if (pointee!=rhs.pointee)
{
if (pointee)
{
pointee->removeReference();
}
pointee = rhs.pointee;
init();
}
return *this;
}
RCPtr<T>&RCPtr<T>::operator=(const RCPtr&rhs)
{
if (pointee!=rhs.pointee)
{
if (pointee)
{
pointee->removeReference();
}
pointee = rhs.pointee;
init();
}
return *this;
}
完整代码可以查看More EffectiveC++ 条款29
#include <iostream>
using namespace std;
//处理reference计数的细节
template<class 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;//指向引用计数器的指针
void init();
};
class RCObject
{
public:
void addReference();
void removeReference();
void makeUnShareable();
bool isShareable()const;
bool isShared()const;
protected:
RCObject();
RCObject(const RCObject&rhs);
RCObject& operator=(const RCObject&rhs);
virtual~RCObject()=0;
private:
int refCOunt;
bool shareable;
};
//开发人员接触的类
class String
{
public:
String(const char*value = "");
const char&operator[](int index)const;
char &operator[](int index);
private:
struct StringValue:public RCObject
{
char *data;
StringValue(const char*initValue);
StringValue(const StringValue&rhs);
void init(const char*initValue);
~StringValue();
};
RCPtr<StringValue>value;
};
RCObject::RCObject():refCOunt(0),shareable(true)
{
}
RCObject::RCObject(const RCObject&):refCOunt(0),shareable(true)
{
}
RCObject& RCObject::operator=(const RCObject&)
{
return *this;
}
RCObject::~RCObject(){}
void RCObject::addReference(){++refCOunt;}
void RCObject::removeReference()
{
if (--refCOunt==0)
delete this;
}
void RCObject::makeUnShareable()
{
shareable=false;
}
bool RCObject::isShareable()const
{
return shareable;
}
bool RCObject::isShared()const
{
return refCOunt>1;
}
//RCPtr根据引用计数的变化对值进行变化
template<class T>
void RCPtr<T>::init()
{
if (pointee==0)
return;
if (pointee->isShareable()==false)
{
pointee = new T(*pointee);
}
pointee->addReference();
}
template<class T>
RCPtr<T>::RCPtr(T*realPtr):pointee(realPtr)
{
init();
}
template<class T>
RCPtr<T>::RCPtr(const RCPtr&rhs):pointee(rhs.pointee)
{
init();
}
template<class T>
RCPtr<T>::~RCPtr()
{
if (pointee)
pointee->removeReference();
}
template<class T>
RCPtr<T>&RCPtr<T>::operator=(const RCPtr&rhs)
{
if (pointee!=rhs.pointee)
{
if (pointee)
pointee->removeReference();
pointee = rhs.pointee;
init();
}
return *this;
}
void String::StringValue::init(const char*initValue)
{
data = new char[strlen(initValue)+1];
strcpy(data,initValue);
}
String::StringValue::StringValue(const char*initvalue)
{
init(initvalue);
}
String::StringValue::StringValue(const StringValue&rhs)
{
init(rhs.data);
}
String::StringValue::~StringValue()
{
delete[]data;
}
//调用的String代码
String::String(const char*value /* = "" */):value(new StringValue(value))
{
}
const char&String::operator[](int index)const
{
return value->data[index];
}
char&String::operator[](int index)
{
if (value->isShared())
{
value = new StringValue(value->data);
}
value->makeUnShareable();
return value->data[index];
}