Effective c++:引用计数

概念:

允许多个等值对象共享同一个实值。

目的:

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;
会导致这样的数据结构
比传统的没有引用计数的效率高,因为不需要分配内存给字符串的第二个副本

//析构函数的实现
//引用次数不是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;
}



写时才复制(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;
}


完整代码可以查看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];
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值