Reference counting的两个技术动机:
由于需要记录“目前共享同一实值”的对象个数,一个reference count(引用计数器)就此引入:
我们需要为每一个字符串值准备一个引用计数,而不是为每一个字符串对象准备,暗示了“对象值”和“引用计数”之间有一种耦合关系:产生一个class,不但存储引用计数,也存储它们追踪的对象值:
class String
{
public:
... //一般的String成员函数安排在这里
private:
struct StringValue{...}; //持有一个引用次数以及一个字符串值
StringValue* value; //String的值
};
//String的定义
class String
{
private:
struct StringValue
{
int refCount;
char* data;
};
StringValue(const char* initValue);
~StringValue();
...
};
//StringValue提供一个地点:
//将"某特定值"以及"共享该值的String对象个数"关联起来。
String::StringValue::StringValue(const char* initValue)
:refCount(1)
{
data = new char[strlen(initValue) + 1];
strcpy(data,initValue);
}
String::StringValue::~StringValue()
{
delete [] data;
}
//String的成员函数从构造函数开始:
class String
{
public:
String(const char* initValue = "");
String(const String& rhs);
...
};
//传入char*创建一个新的StringValue对象
String::String(const char* initValue) : value(new StringValue(initValue));
{}
//String的复制构造函数很有效率
String::String(const String& rhs):
value(rhs.value)
{
++value -> refCount;
}
//运用
String s1("More Effective C++");
String s2(s1);
//新生成的String对象与被复制的对象共享相同的StringValue对象
以上只需将指针复制一份,并将引用从次数加1,不需要分配和归还内存,效率更高。
//String的析构函数
class String
{
public:
~String();
};
String::~String()
{
if(--value->refCount == 0) delete value;
//只有当唯一的用户被析构,String析构函数才销毁StringValue
}
//String的赋值操作符
class String
{
public:
...
String& operator = (const String&& rhs);
};
String& String::operator = (const String& rhs)
{
if(value == rhs.value)
return *this;
if(--value->refCount == 0)
delete value;
value = rhs.value;
++value->refCount;
return *this;
}
方括号操作符[ ]
:它允许字符串中的个别字符被读取或被写;
class String
{
public:
const char& operator[](int index) const;//针对const Strings
char& operator[](int index); //针对non-const String
...
};
//const版本:只读动作;字符串内容不受影响
const char& String::operator[](int index) const
{
return value->data[index];
}
//non-const版本:
//可能用来读取一个字符串,也可能用来写一个字符串
String s;
...
cout << s[3]; //读取动作
s[5] = 'x'; //写入动作
为了安全实现出non-const operator[]
,我们必须确保没有其他任何“共享同一个StringValue”的String对象因写动作而改变:
char& String::operator[](int index)
{
//如果本对象和其他String对象共享同一实值
//就分割(复制)出另一副本供本对象自己使用
if(value->refCount > 1)
--value->refCount; //将目前实值的引用频次减1,因为我们不再使用
//为自己做一份新的副本
value = new StringValue(value->data);
//返回一个reference,代表我们这个“绝对不被共享”的
//StringValue对象内的一个字符。
return value->data[index];
}
为每一个StringValue对象加上一个标志(flag)变量,用以指示可否被共享:
//修改版
class String
{
private:
struct StringValue
{
int refCount;
bool shareable; //新增此行
char* data;
};
StringValue(const char* initValue);
~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;
}
//复制函数的新行为
String::String(const String& rhs)
{
if(rhs.value->shareable)
{
value = rhs.value;
++value->refCount;
}
else
{
value = new StringValue(rhs.value->data);
}
}
//Non-const operator[]是唯一将shareble设为false者:
char& String::operator[](int index)
{
if(value->refCount > 1)
--value->refCount;
value = new StringValue(value->data);
value->shareable = false; //新增此行
return value->data[index];
}
产生一个base class RCObject,作为“reference-counted对象”之用。
任何class希望自动拥有reference counting能力,都必须继承自这个类:
//RCObject定义
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;
};
//RCObject实现
RCObject::RCObject()
:refCount(0),shareable(true){}
RCObject::RCObject(const RCObject& rhs)
:refCount(0),shareable(true){}
RCObject& RCObject::operator = (const RCObject& rhs)
{ return *this; }
RCObject::~RCObject(){}
void RCObject::addReference()
{
++refCount;
}
void RCObject::removeReference()
{
if(--refCount == 0)
delete this;
}
void RCObject::markUnshareable()
{
shareable = false;
}
bool RCObject::isShareable() const
{
return shareable;
}
bool RCObject::isShared() const
{
return refCount > 1;
}
//StringValue继承自RCObject
class String
{
private:
//StringValue的成员函数不再处理refCount字段,改由RCObject掌管
struct StringValue: public RCObject
{
char* data;
StringValue(const char* initValue);
~StringValue();
};
...
};
String::StringValue::StringValue(const char* initValue)
{
data = new char[strlen(initValue) + 1];
stpcpy(data,initValue);
}
String::StringValue::~StringValue()
{
delete [] data;
}
我们希望能够把这一系列调用动作移到一个可复用的class内,这么一来可以让诸如String之类的classes的作者不必操心reference counting的任何细节。
//下面这个模板用来产生智能指针指向reference-counted对象:
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<T>
RCPtr<T>::RCPtr(T* realPtr = 0)
:pointee(realPtr)
{
init();
}
template<T>
RCPtr<T>::RCPtr(const RCPtr& rhs)
pointee(rhs.pointee)
{
init();
}
template<T>
void RCPtr<T>::init()
{
if(pointee == NULL)
return ;
if(pointee->isShareble() == false)
pointee = new T(*pointee);
pointee->addReference();
}
以上错误在于:init!
pointee = new T(*pointee)
构造新的T对象,但是RCPtr在String类内部,T将是String::StringValue,所以我们必须为String::StringValue加上深复制函数:
class String
{
private:
struct StringValue: public RCObject
{
StringValue(const StringValue& rhs);
...
};
};
String::StringValue::StringValue(const StringValue& rhs)
{
data = new char[strlen(rhs.data) + 1];
strcpy(data,rhs.data);
}
template<class T> //template class,用来产生
class RCPtr //smart pointers-to-Tobjects;
{ //T必须继承自RCObject
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 //base class, 用于reference-counted objects
{
public:
void addReference();
void removeReference();
void markUnshanreable();
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 //应用性class,这是应用程序开发人员接触的层面
{
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::RCObject()
:refCount(0),shareable(true){}
RCObject::RCObject(const RCObject& rhs)
:refCount(0),shareable(true){}
RCObject& RCObject::operator = (const RCObject& rhs)
{ return *this; }
RCObject::~RCObject(){}
void RCObject::addReference()
{ ++refCount; }
void RCObject::removeReference()
{
if(--refCount == 0)
delete this;
}
void RCObject::markUnshanreable()
{ 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 = 0)
:pointee(realPtr)
{
init();
}
template<class T>
RCPtr<T>::RCPtr(const RCPtr& rhs)
:pointee(realPtr)
{
init();
}
template<class T>
RCPtr<T>::~RCPtr()
{
if(pointee)
pointee->removeReference();
}
template<class T>
RCPtr& RCPtr<T>::operator = (const RCPtr& rhs)
{
if(pointee != rhs.pointee)
{
if(pointee)
pointee->removeReference();
pointee = rhs.pointee;
init();
}
return *this;
}
template<class T>
T* RCPtr<T>::operator->() const
{ return pointee; }
template<class T>
T& RCPtr<T>::operator*() const
{ return *pointee; }
//String::StringValue实现
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(initValue)){}
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->markUnshanreable();
return value->data[index];
}
就像“StringValue只能实现细节,不需让String的用户知道”一样;
CountHolder也是实现细节,不需让RCWidget的用户知道。
事实上它是RCIPtr的实现细节,所以嵌套放入RCIPtr class内部。
RCIPtr实现如下:
template<class T>
class RCIPtr
{
public:
RCIPtr(T* realPtr = 0);
RCIPtr(const RCIPtr& rhs);
~RCIPtr();
RCIPtr& operator = (const RCIPtr& rhs);
const T* operator->() const;
T* operator->();
const T& operator*() const;
T& operator*();
private:
struct CountHolder: public RCObject
{
~CountHolder{ delete pointee; }
T* pointee;
};
CountHolder* counter;
void init();
void makeCopy();
};
template<class T>
void RCIPtr<T>::init()
{
if(counter->isShareable == false)
{
T* oldValue = counter->pointee;
counter = new CountHolder;
counter->pointee = new T(*pointee);
}
pointee->addReference;
}
template<class T>
RCIPtr<T>::RCIPtr(T* realPtr)
:counter(new CountHolder)
{
counter->pointee = realPtr;
init();
}
template<class T>
RCIPtr<T>::RCIPtr(const RCIPtr& rhs)
:counter(rhs.counter)
{
init();
}
template<class T>
RCIPtr<T>::~RCIPtr()
{
counter->removeReference;
}
template<class T>
RCIPtr& RCIPtr<T>::operator = (const RCIPtr& rhs)
{
if(counter != rhs.counter)
{
counter->removeReference();
counter = rhs.counter;
init();
}
return *this;
}
template<class T>
const T* RCIPtr<T>::operator->() const
{
return counter->pointee;
}
template<class T>
const T& RCIPtr<T>::operator*() const
{
return *(counter->pointee);
}
什么时候最适合reference counting技术: