C++::实现String类的引用计数形式 - 高小调博客

C++::实现String类的引用计数形式

由前文得知,在String类中的浅拷贝形式中程序将同一块空间被释放了两次,因而发生崩溃.

那么,只要我们对当前共享pStr指针对象的个数做计数.

只有当最后一个对象被析构时,才真正的释放内存,这样的话程序就不会有问题了.

String类的这种版本,被称之为引用计数.

废了这么多话,可能有些晦涩难懂,下面,我把代码贴出来,供大家参考:

引用计数初级版

String引用计数初级版相对于浅拷贝版,多了一个成员count,用来记录共享pStr指针的个数.

实现起来相对简单,因此,我只给出原型.有兴趣的童鞋可以自己来尝试实现一下.

//引用计数的初级版
class String{
	//构造函数
	String(const char *Str="");
	//拷贝构造
	String(const String &s);
	//赋值运算符重载
	String &operator=(const String &s);
	//析构函数
	~String()
private:
	//存放字符串
	char *_pStr;
	//存放共享pStr对象的个数
	int *_iCount;
}

引用计数最终版

String引用计数最终版,参考了new[]/delete[]开辟空间时的做法.

给pStr多申请4个字节,用来代替前文中iCount变量.

/*
*本代码版权归高小调博客所有 
*作者:最近头比较大,不知道怎么有效学习C++的高小调
*日期:2016-10-21
*代码功能:String类的引用计数版本 
*/
#include<iostream>
class String{
public:
	//构造函数,默认初始化为空串
	String(const char *pStr = ""){
		//防止String s(NULL);
		if(NULL != pStr){
			//pStr不为空时,开辟一段内存
			//多申请4个字节用来存储当前共享pStr指针对象的个数
			_pStr = new char[strlen(pStr)+1+4];
			//将前4个字节的内容赋值为1
			*((int *)_pStr) = 1;
			//_pStr向后偏移4个字节,偏移到字符串域
			_pStr += 4;
			//将源字符串拷贝过去
			strcpy(_pStr,pStr);
		}else{
			//pStr为空时,开辟5个字节,前四个字节存储对象个数
			_pStr = new char[5];
			//将前4个字节的内容赋值为1
			*((int *)_pStr) = 1;
			//_pStr向后偏移4个字节,偏移到字符串域
			_pStr += 4;
			*_pStr = '\0';
		}
	}
	//拷贝构造函数,将_pStr初始化为被拷贝对象的pStr指针
	String(String &s)
		:_pStr(s._pStr){
		//计数器加1
		++(*((int *)(_pStr-4)));

	}
	//赋值运算符重载
	String &operator=(const String &s){
		//判断是否自身给自身赋值
		if(this!=&s){
			//如果this对象的计数器减一后为0
			if(0 == --(*((int *)(_pStr-4)))){
				//释放this对象的pStr
				delete (_pStr-4);
			}
			//_pStr指向新区域,且计数器加1
			_pStr = s._pStr;
			++(*((int *)(_pStr-4)));
		}
		return *this;
	}
	//析构函数
	~String(){
		//如果this对象的计数器减一后为0
		if(0 == --(*((int *)(_pStr-4)))){
			//释放this对象的pStr
			delete (_pStr-4);
			_pStr = NULL;
		}
	}
private:
	//前4个字节用来存放对象个数
	char *_pStr;
};
int main(){
	String s1("Hello");
	String s2(s1);
	String s3;
	s3 = s2;
	return 0;
}

String引用计数版本String深拷贝版相比:节省了空间、更节省了开辟这些内存的时间,显著提高了程序的性能!

但也存在一个问题,s1、s2、s3共用一块区域

如果任意一个字符串需要被修改时,那么指向这块区域的所有字符串都遭到了修改

那么问题来了:有没有什么好的解决方案呢?

答案:有的!详见下文,String类的写时拷贝形式.

ps:啦啦啦...今天好好整理下C++的东西.

上一篇:
下一篇: