三、引用计数基类和智能指针实现的String类
//RCObject.h
#ifndef RCOBJECT_H
#define RCOBJECT
//引用计数基类
class RCObject{
public:
void addReference();//增加引用计数
void removeReference();//减少引用计数,如果变为0,销毁对象
void markUnshareable();//将追踪其值是否可共享的成员设为false
bool isShareable() const;//判断其值是否可共享
bool isShared() const;//判断其值是否正在被共享
int getRefCount();//返回引用计数
protected:
RCObject();//构造函数
RCObject(const RCObject& rhs);//拷贝构造函数
RCObject& operator=(const RCObject& rhs);//拷贝赋值运算符
virtual ~RCObject() = 0;//析构函数
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;
}
#endif
//RCPtr.h
#ifndef RCPTR_H
#define RCPTR_H
//智能指针模板类,用来自动执行引用计数类成员的操控动作
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;
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; }
#endif
//String.h
#ifndef STRING_H
#define STRING_H
#define _CRT_SECURE_NO_WARNINGS
#include"RCObject.h"
#include"RCPtr.h"
#include<iostream>
class String {
public:
String(const char *value = "");//构造函数
const char& operator[](int index) const;//重载[]运算符,针对const Strings
char& operator[](int index);//重载[]运算符,针对non-const Strings
int getRefCount();//返回引用计数
friend std::istream& operator>>(std::istream& is, const String& str);//重载>>运算符
friend std::ostream& operator<<(std::ostream& os, const String& str);//重载<<运算符
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];
}
//返回引用计数
int String::getRefCount(){
return value->getRefCount();
}
//重载>>运算符
std::istream& operator>>(std::istream& is, const String& str){
is >> str.value->data;
return is;
}
//重载<<运算符
std::ostream& operator<<(std::ostream& os, const String& str){
os << str.value->data;
return os;
}
#endif
//main.cpp
#include"String.h"
#include<iostream>
using namespace std;
int main(){
String str1("hello world");
String str2 = str1;//调用拷贝构造函数
String str3;//调用默认构造函数
str3 = str2;//调用拷贝赋值运算符
cout << "str1的引用计数是:" << str1.getRefCount() << endl; // 3
cout << "str2的引用计数是:" << str2.getRefCount() << endl; // 3
cout << "str3的引用计数是:" << str3.getRefCount() << endl; // 3
str1[0] = 'H';//调用针对non-const Strings的重载[]运算符
cout << str1 << endl; //"Hello world"
cout << str2 << endl;//"hello world"
cout << str3 << endl;//"hello world"
cout << "str1的引用计数是:" << str1.getRefCount() << endl;//1
cout << "str2的引用计数是:" << str2.getRefCount() << endl;//2
cout << "str3的引用计数是:" << str3.getRefCount() << endl;//2
system("pause");
return 0;
}
上述实现的String类的数据结构如下:
和上一个用dumbpointers实现的String类比较:第一,这个版本精简了许多,因为RCPtr类做掉了许多原本落在String身上的引用计数杂务;第二,智能指针几乎毫无间隙地取代了dumb pointer。
四、将引用计数加到既有的类身上
//RCObject.h
#ifndef RCOBJECT_H
#define RCOBJECT
//引用计数基类
class RCObject{
public:
void addReference();//增加引用计数
void removeReference();//减少引用计数,如果变为0,销毁对象
void markUnshareable();//将追踪其值是否可共享的成员设为false
bool isShareable() const;//判断其值是否可共享
bool isShared() const;//判断其值是否正在被共享
int getRefCount();//返回引用计数
protected:
RCObject();//构造函数
RCObject(const RCObject& rhs);//拷贝构造函数
RCObject& operator=(const RCObject& rhs);//拷贝赋值运算符
virtual ~RCObject() = 0;//析构函数
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;
}
#endif
//RCIPtr.h
#ifndef RCIPTR_H
#define RCIPTR_H
#include "RCObject.h"
//智能指针模板类,用来自动执行引用计数类成员的操控动作
template<typename 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();//copy-on-write中的copy部分
};
//共同的初始化操作
template <typename T>
void RCIPtr<T>::init(){
if (counter->isShareable() == false){
T* oldValue = counter->pointee;
counter = new CountHolder;
counter->pointee = new T(*oldValue);
}
counter->addReference();
}
//构造函数
template <typename T>
RCIPtr<T>::RCIPtr(T* realPtr) :counter(new CountHolder){
counter->pointee = realPtr;
init();
}
//拷贝构造函数
template <typename T>
RCIPtr<T>::RCIPtr(const RCIPtr& rhs) :counter(rhs.counter){
init();
}
//析构函数
template <typename T>
RCIPtr<T>::~RCIPtr(){
counter->removeReference();
}
//拷贝赋值运算符
template <typename T>
RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs){
if (counter != rhs.counter){
counter->removeReference();
counter = rhs.counter;
init();
}
return *this;
}
//重载->运算符,const版本
template<typename T>
const T* RCIPtr<T>::operator->() const { return counter->pointee; }
//重载*运算符,non-const版本
template<typename T>
const T& RCIPtr<T>::operator*() const { return *(counter->pointee); }
//copy-on-write中的copy部分
template <typename T>
void RCIPtr<T>::makeCopy(){
if (counter->isShared()){
T* oldValue = counter->pointee;
counter->removeReference();
counter = new CountHolder;
counter->pointee = new T(*oldValue);
counter->addReference();
}
}
//重载->运算符,non-const版本
template <typename T>
T* RCIPtr<T>::operator->(){
makeCopy();
return counter->pointee;
}
//重载*运算符,non-const版本
template <typename T>
T& RCIPtr<T>::operator*(){
makeCopy();
return *(counter->pointee);
}
#endif
//Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <iostream>
class Widget{
public:
Widget(int s = 0) :size(s){}
Widget(const Widget& rhs) { size = rhs.size; }
~Widget(void) {}
Widget& operator=(const Widget& rhs){
if (this == &rhs)
return *this;
this->size = rhs.size;
return *this;
}
void doThis() { std::cout << "doThis()" << std::endl; }
int showThat() const {
std::cout << "showThat()" << std::endl;
return size;
}
private:
int size;
};
#endif
//RCWidget.h
#ifndef RCWIDGET_H
#define RCWIDGET_H
#include "RCIPtr.h"
#include "Widget.h"
class RCWidget{
public:
RCWidget(int size = 0) :value(new Widget(size)){}
~RCWidget() {}
void doThis() { value->doThis(); }
int showThat() const { return value->showThat(); }
private:
RCIPtr<Widget> value;
};
#endif
//main.cpp
#include"RCWidget.h"
using namespace std;
int main(){
RCWidget rc1(5);
rc1.doThis();
cout << rc1.showThat() << endl;
RCWidget rc2(rc1);
rc2.doThis();
cout << rc2.showThat() << endl;
system("pause");
return 0;
}
上述例子的数据结构如下:
RCIRtr和RCPtr之间有两个差异:第一,RCPtr对象直接指向实值,而RCIPtr对象通过中间层CountHolder对象指向实值;第二,RCIPtr将operator->和operator*重载了,这样只要有non-const access发生于被指物身上,copy-on-write就会自动执行。
总结:引用计数的实现需要成本。每一个拥有计数能力的实值都有一个引用计数器,而大部分操作都需要能够以某种方式检查或处理这个引用计数器,因此对象的实值需要更多内存。而且引用计数的底层源代码比没有引用计数的复杂的多。
引用计数是个优化计数,其适用前提是对象常常共享实值。使用引用计数改善效率的时机有以下两个:第一,相对多数的对象共享相对少量的实值;第二,对象实值的产生或销毁成本很高,或是它们使用许多内存。