C++ 编程规范-string类型的实现

本文详细介绍了C++中string类型的两种实现方式:eager-copy和copy-on-write。通过示例展示了eager-copy方式可能导致的内存浪费,并提出了一种使用copy-on-write策略实现的自定义mystring类。在自定义类中,通过引用计数来实现字符串共享,降低了内存开销。同时,文章强调了当类中包含指针成员时,需要手动定义拷贝构造函数和赋值拷贝运算符的重要性。
摘要由CSDN通过智能技术生成

1. string类型字符串存储方式的简单说明

string实现方式:比较典型的有eager-copy(贪婪拷贝);copy-on-write(写时复制);small string optimization(短字符串优化)方式。

string str1 = "I love China"
string str2 = str1;
printf("str1存储的地址:%p".str1.c_str())
printf("str2存储的地址:%p".str2.c_str())

在这里插入图片描述
可以看出采用eager-copy方式实现。浪费内存了。
在这里插入图片描述
利用写时复制的方式实现自己的string类。

2. 通过copy-on-write方式实现string类型

1. 框架与技术设计

一般的string类设计
class mystring
{
public:
	mystring(const char* tmpstr = "")  // 
	{

	}
	mystring(const mystring& tmpstr) {
		point = new char[strlen(tmpstr.point) + 1];
		strcpy(point, tmpstr.point);
	}
	mystring& operator= (const mystring& tmpstr) {
		if (this == &tmpstr) {
			return *this;
		}
		delete[] point;
		// 如果要这么写,下图中,kxstr3和kxstr1就不是指向同一块内存了
		point = new char[strlen(tmpstr.point) + 1];  // 给字符串末尾\0留位置
		strcpy(point, tmpstr.point);
		return *this;
	}
private:
	char* point;  // 指向实际的字符串
};

mystring kxstr1("I love China");
mystring kxstr2 = ("I love China");

mystring kxstr3 = kxstr1;  // 调用拷贝构造函数
kxstr2 = kxstr1;  // 调用赋值拷贝运算符

在这里插入图片描述

改造后的string类设计

如果采用以上的拷贝构造函数,那么无法满足图中的共享内存的方式。接下来我们重新写一个类stringvalue也就是把要保存的字符串以及对字符串的引用计数统一的保存在一个对象中。

class mystring
{
public:
	mystring(const char* tmpstr = ""): pvalue(new stringvalue(tmpstr))  //构造函数中就把stringvalue构造出来!!! 
	{

	}
	// 1. pvalue都指向堆中的stringvalue对象
	// 2. 引用计数+1
	mystring(const mystring& tmpstr):pvalue(tmpptr.pvalue) {  // 拷贝构造函数
		++pvalue->refcount;
	}
	mystring& operator= (const mystring& tmpstr) {
		if (this == &tmpstr) {
			return *this;
		}
		--pvalue->refcount;  // 本身存在对象(*this),自己所指向的字符串引用计数先减一
		if(pvalue->refcount == 0)
			delete pvalue;  // 如果原来指向的堆中的引用计数为0了,那么删除原来的指针
		pvalue = tmpstr.pvalue;
		++pvalue -> refcount;
	}
	~mystring()
	{
		--pvalue->refcount;
		if (pvalue->refcount==0)
		{
			delete pvalue;
		}
	}
private:
	//char* point;  // 指向实际的字符串
	// 类中类
	struct stringvalue
	{
		size_t refcount;  // 引用计数
		char* point;  // 指向实际字符串的指针
		stringvalue(const char* tmpstr):refcount(1) // 构造函数
		{
			point = new char[strlen(tmpstr) + 1];
			strcpy(point, tmpstr.point);
		}
		~stringvalue()
		{
			delete[] point;
		}
	}
};
  1. 创建两个不同的mystring对象时,及时字符串相同,也不会共享内存。他们的关系如图所示:
mystring kxstr1("I love China");
mystring kxstr2("I love China");

在这里插入图片描述

mystring kxstr3 = kxstr1;  // 调用mystring类的拷贝构造函数
kxstr2 = kxstr1;  // 调用mystring类的赋值拷贝运算符

记住一个原则,如果一个类中包含有指针成员(比如mystring类中的pvalue),那么一般需要手工为该类书写拷贝构造函数和赋值拷贝运算符。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值