• 【more effective c++读书笔记】【第5章】技术(5)——Reference counting(引用计数)(2)


    三、引用计数基类和智能指针实现的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就会自动执行。

    总结:引用计数的实现需要成本。每一个拥有计数能力的实值都有一个引用计数器,而大部分操作都需要能够以某种方式检查或处理这个引用计数器,因此对象的实值需要更多内存。而且引用计数的底层源代码比没有引用计数的复杂的多。

    引用计数是个优化计数,其适用前提是对象常常共享实值。使用引用计数改善效率的时机有以下两个:第一,相对多数的对象共享相对少量的实值;第二,对象实值的产生或销毁成本很高,或是它们使用许多内存。


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    PAT (Advanced Level) 1080. Graduate Admission (30)
    PAT (Advanced Level) 1079. Total Sales of Supply Chain (25)
    PAT (Advanced Level) 1078. Hashing (25)
    PAT (Advanced Level) 1077. Kuchiguse (20)
    PAT (Advanced Level) 1076. Forwards on Weibo (30)
    PAT (Advanced Level) 1075. PAT Judge (25)
    PAT (Advanced Level) 1074. Reversing Linked List (25)
    PAT (Advanced Level) 1073. Scientific Notation (20)
    PAT (Advanced Level) 1072. Gas Station (30)
    PAT (Advanced Level) 1071. Speech Patterns (25)
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4921353.html
Copyright © 2020-2023  润新知