当前位置: 首页 > article >正文

C++中的字符串实现

短字符串优化(SSO)

实现1

在这里插入图片描述

实现2

在这里插入图片描述

写时复制

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstring>
using std::cout;
using std::endl;

// 引用计数存放的位置
// 1. 存放在栈上 --- 不行
// 2. 存放在全局静态区 --- 不行
// 3. 只能放在堆上
class String
{
public:
	String();
	String(const char* pstr);
	String(const String& rhs);
	String& operator=(const String& rhs);
	~String();
	const char* c_str() const;
	int getRefCount()const;
	friend std::ostream& operator<<(std::ostream& os, const String& rhs);
	char& operator[](size_t index);
private:
	size_t size()const;
private:
	char* _pstr;
};
String::String() :_pstr(new char[5] + 4) 
{// 5: 引用计数+‘\0’  4:让其直接指向数据的位置
	//cout << "String()" << endl;
	*(int*)(_pstr - 4) = 1;
}
String::String(const char* pstr):_pstr(new char[strlen(pstr) + 5]()+4)/*_pstr(new char(strlen(pstr)+1))*/
{
	//cout << "String::String(const char* pstr)" << endl;
	strcpy(_pstr,pstr);
	(*(int*)(_pstr - 4)) = 1;
}
// String s2(s1)
String::String(const String& rhs):_pstr(rhs._pstr) // 浅拷贝
{
	//cout << "String::String(const String& rhs)" << endl;
	(*(int*)(_pstr - 4))++;
}
String& String::operator=(const String& rhs)
{
	if (&rhs != this)   //1. 自赋值
	{
		// 2. 释放左操作
		(*(int*)(_pstr - 4))--;
		if (0 == (*(int*)(_pstr - 4)))
		{
			delete[](_pstr - 4);
		}
		// 3. 深拷贝(浅拷贝)
		_pstr = rhs._pstr;
		(*(int*)(_pstr - 4))++;
	}
	return *this;
}
String::~String()
{
	cout << "~String()" << endl;
	(*(int*)(_pstr - 4))--;
	if (0 == (*(int*)(_pstr - 4)))
	{
		delete[](_pstr - 4);
	}
}
const char* String::c_str() const
{
	return _pstr;
}
int String::getRefCount() const
{
	return *(int*)(_pstr - 4);
}
std::ostream& operator<<(std::ostream& os, const String& rhs)
{
	if (rhs._pstr != NULL) {
		os << rhs._pstr << endl;
	}
	return os;
}
size_t String::size()const
{
	return strlen(_pstr);
}
char& String::operator[](size_t index)
{
	if (index > size()) {
		static char charnull = '\0';
		return charnull;
	}
	else {
		if (getRefCount() > 1) { // 考虑是不是共享的
			// 执行深拷贝
			int len = size();
			char* tmp = new char[len+5]()+4;
			strcpy(tmp,_pstr);

			(*(int*)(_pstr - 4))--;  // 注意这里不需要看是否等于0,因为getRefCount() > 1
			_pstr = tmp;
			(*(int*)(_pstr - 4)) = 1;
			/*return _pstr[index];*/ // 这个要写到括号之外,可能这个字符串没有被共享
		}
		return _pstr[index];
	}
}

//std::ostream& operator<<(std::ostream& os, char ch)
//{
//	os << "std::ostream& operator<<(std::ostream& os, char ch)" << endl;
//	os << ch;
//	return os;
//}
int main(void)
{
	String s1("hello");
	String s2(s1);
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;

	printf("s1`address = %p\n",s1.c_str());
	printf("s2`address = %p\n",s2.c_str());

	String s3("world");
	cout << "s3 = " << s3 << endl;
	cout << "s3 RefCount= " << s3.getRefCount() << endl;

	cout << endl << "使用s3对s1进行赋值操作" << endl;
	s3 = s1;
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s1 RefCount= " << s1.getRefCount() << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;
	cout << "s3 RefCount= " << s3.getRefCount() << endl;

	printf("s1`address = %p\n", s1.c_str());
	printf("s2`address = %p\n", s2.c_str());
	printf("s3`address = %p\n", s3.c_str());

	cout << endl << endl << "对s3[0]执行写操作" << endl;
	s3[0] = 'H';
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s1 RefCount= " << s1.getRefCount() << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;
	cout << "s3 RefCount= " << s3.getRefCount() << endl;
	printf("s1`address = %p\n", s1.c_str());
	printf("s2`address = %p\n", s2.c_str());
	printf("s3`address = %p\n", s3.c_str());

	/*如何区分是对[] 读还是写
		cout<<s[1]  是进行的读操作;  可以对[]进行重载
		s[1] = '1'  是进行的写操作;  可以对=进行重载
	*/
	// 读操作
	//cout << s1[1] << endl;
	return 0;
}
  • 如何区分什么什么时候读,什么时候写

    • 通过一个中间类型CharProxy,并且重载他的operator=和operator<<函数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstring>
using std::cout;
using std::endl;

// 引用计数存放的位置
// 1. 存放在栈上 --- 不行
// 2. 存放在全局静态区 --- 不行
// 3. 只能放在堆上
class String
{
public:
	String();
	String(const char* pstr);
	String(const String& rhs);
	String& operator=(const String& rhs);
	~String();
	const char* c_str() const;
	int getRefCount()const;
	friend std::ostream& operator<<(std::ostream& os, const String& rhs);
private:
	class CharProxy {
	public:
		CharProxy( String& self, size_t idx) :_self(self), _idx(idx) {}
		char& operator = (const char& ch); // 写操作
		/*{
			_self[_idx] = ch;
			return _self[_idx];
		}*/
		friend std::ostream& operator<<(std::ostream& os, const CharProxy& ch);
	private:
		String &_self; // 此时String是不完整类型
		size_t _idx;
	};
public:
	friend std::ostream& operator<<(std::ostream& os, const CharProxy& ch);
	//char& operator[](size_t index);
	CharProxy  operator[](size_t idx)
	{
		return CharProxy(*this,idx);
	}
private:
	void initRefCount();
	void increaseRefCount();
	void decreaseRefCount();
	void release();
	size_t size()const;
private:
	char* _pstr;
};
String::String() :_pstr(new char[5] + 4) 
{// 5: 引用计数+‘\0’  4:让其直接指向数据的位置
	//cout << "String()" << endl;
	initRefCount();
}
String::String(const char* pstr):_pstr(new char[strlen(pstr) + 5]()+4)/*_pstr(new char(strlen(pstr)+1))*/
{
	//cout << "String::String(const char* pstr)" << endl;
	strcpy(_pstr,pstr);
	//(*(int*)(_pstr - 4))--;
	initRefCount();
}
// String s2(s1)
String::String(const String& rhs):_pstr(rhs._pstr) // 浅拷贝
{
	//cout << "String::String(const String& rhs)" << endl;
	//(*(int*)(_pstr - 4))++;
	increaseRefCount();
}
String& String::operator=(const String& rhs)
{
	if (&rhs != this)   //1. 自赋值
	{
		// 2. 释放左操作
		//(*(int*)(_pstr - 4))--;
		/*decreaseRefCount();
		if (0 == (*(int*)(_pstr - 4)))
		{
			delete[](_pstr - 4);
		}*/
		release();
		// 3. 深拷贝(浅拷贝)
		_pstr = rhs._pstr;
		//(*(int*)(_pstr - 4))++;
		increaseRefCount();
	}
	return *this;
}
String::~String()
{
	//cout << "~String()" << endl;
	//(*(int*)(_pstr - 4))--;
	//decreaseRefCount();
	//if (0 == (*(int*)(_pstr - 4)))
	//{
	//	delete[](_pstr - 4);
	//}
	release();
}
void String::initRefCount()
{
	*(int*)(_pstr - 4) = 1;
}
void String::increaseRefCount()
{
	(*(int*)(_pstr - 4))++;
}
void String::decreaseRefCount()
{
	(*(int*)(_pstr - 4))--;
}
void String::release()
{	
	decreaseRefCount();
	if (0 == (*(int*)(_pstr - 4)))
	{
		delete[](_pstr - 4);
	}
}
const char* String::c_str() const
{
	return _pstr;
}
int String::getRefCount() const
{
	return *(int*)(_pstr - 4);
}
std::ostream& operator<<(std::ostream& os, const String& rhs)
{
	if (rhs._pstr != NULL) {
		os << rhs._pstr << endl;
	}
	return os;
}
size_t String::size()const
{
	return strlen(_pstr);
}
char& String::CharProxy::operator = (const char& ch) // 写操作
{
	if (_idx > _self.size()) 
	{
		static char charnull = '\0';
		return charnull;
	}
	else 
	{
		if (_self.getRefCount() > 1) { // 考虑是不是共享的
			// 执行深拷贝
			int len = _self.size();
			char* tmp = new char[len+5]()+4;
			strcpy(tmp, _self._pstr);
			//(*(int*)(_pstr - 4))--;  // 注意这里不需要看是否等于0,因为getRefCount() > 1
			_self.decreaseRefCount();
			_self._pstr = tmp;
			_self.initRefCount();
			/*return _pstr[index];*/ // 这个要写到括号之外,可能这个字符串没有被共享
		}
		_self._pstr[_idx] = ch;
		return _self._pstr[_idx];
	}
}
//双友元的设置
std::ostream& operator<<(std::ostream& os, const String::CharProxy& rhs)
// 注意这个函数既要左CharProxy的友元也要作为String的友元(不然上面的代码const String::CharProxy& ch处会报错)
{
	os << rhs._self._pstr[rhs._idx];
	return os;
}
//char& String::operator[](size_t index)
//{
//	if (index > size()) {
//		static char charnull = '\0';
//		return charnull;
//	}
//	else {
//		if (getRefCount() > 1) { // 考虑是不是共享的
//			// 执行深拷贝
//			int len = size();
//			char* tmp = new char[len+5]()+4;
//			strcpy(tmp,_pstr);
//
//			//(*(int*)(_pstr - 4))--;  // 注意这里不需要看是否等于0,因为getRefCount() > 1
//			decreaseRefCount();
//			_pstr = tmp;
//			//(*(int*)(_pstr - 4)) = 1;
//			initRefCount();
//			/*return _pstr[index];*/ // 这个要写到括号之外,可能这个字符串没有被共享
//		}
//		return _pstr[index];
//	}
//}

//std::ostream& operator<<(std::ostream& os, char ch)
//{
//	os << "std::ostream& operator<<(std::ostream& os, char ch)" << endl;
//	os << ch;
//	return os;
//}
int main(void)
{
	String s1("hello");
	String s2(s1);
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;

	printf("s1`address = %p\n",s1.c_str());
	printf("s2`address = %p\n",s2.c_str());

	String s3("world");
	cout << "s3 = " << s3 << endl;
	cout << "s3 RefCount= " << s3.getRefCount() << endl;

	cout << endl << "使用s3对s1进行赋值操作" << endl;
	s3 = s1;
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s1 RefCount= " << s1.getRefCount() << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;
	cout << "s3 RefCount= " << s3.getRefCount() << endl;

	printf("s1`address = %p\n", s1.c_str());
	printf("s2`address = %p\n", s2.c_str());
	printf("s3`address = %p\n", s3.c_str());

	cout << endl << endl << "对s3[0]执行写操作" << endl;
	s3[0] = 'H';
	// 首先会调用s1.operator[](1)返回一个CharProxy对象,然后调用CharProxy的operatpr=()函数
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s1 RefCount= " << s1.getRefCount() << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;
	cout << "s3 RefCount= " << s3.getRefCount() << endl;
	printf("s1`address = %p\n", s1.c_str());
	printf("s2`address = %p\n", s2.c_str());
	printf("s3`address = %p\n", s3.c_str());

	/*如何区分是对[] 读还是写
		cout<<s[1]  是进行的读操作;  可以对[]进行重载
		s[1] = '1'  是进行的写操作;  可以对=进行重载
		s[1] = '1'   .  
		char = char 两个char是不能被重载的,因为 运算符重载的第一条规则,参数必须要有一个自定义类型或者enum
		CharProxy = char就可以重载了	
		
		可以先重载一下[],让他返回一个CharProxy对象,然后重载CharProxy的operator=和operator<<函数
		CharProxy operator[](size idx);
		CharProxy = char;
	*/
	// 读操作
	cout << endl << endl << "对s1[1]执行读操作操作" << endl;
	cout << s1[1] << endl; 
	// 首先会调用s1.operator[](1)返回一个CharProxy对象,然后调用CharProxy的operator<<()函数
	cout << "s1 = " << s1 << endl;
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s1 RefCount= " << s1.getRefCount() << endl;
	cout << "s2 RefCount= " << s2.getRefCount() << endl;
	cout << "s3 RefCount= " << s3.getRefCount() << endl;
	printf("s1`address = %p\n", s1.c_str());
	printf("s2`address = %p\n", s2.c_str());
	printf("s3`address = %p\n", s3.c_str());
	return 0;
}


//https://www.bilibili.com/video/BV1VM4m12754?t=1190.2&p=58

上面会出现,双友元声明,可以只重载operator=,不重载<< 和一个类型转换函数

  • //双友元的设置
    std::ostream& operator<<(std::ostream& os, const String::CharProxy& rhs)
    // 注意这个函数既要左CharProxy的友元也要作为String的友元(不然上面的代码const String::CharProxy& ch处会报错)
    {
    	os << rhs._self._pstr[rhs._idx];
    	return os;
    }
    
    // cout<<s1[1]  CharProxy-> char
    
  • 改为

    • String::CharProxy::operator char()  // 注意类型转换函数在类外的定义的形式operator char都放在最后
      {
      	return _self._pstr[_idx];
      }
      

string的实现

#include<iostream>
#include<cstring>
#include<vector>
using std::cout;
using std::endl;

class String 
{
	friend bool operator==(const String& lhs, const String& rhs);
	friend bool operator!=(const String& lhs, const String& rhs);
	friend bool operator>(const String& lhs, const String& rhs);
	friend bool operator<(const String& lhs, const String& rhs);
	friend bool operator<=(const String& lhs, const String& rhs);
	friend bool operator>=(const String& lhs, const String& rhs);
	friend std::ostream& operator<<(std::ostream& os, const String& s);
	friend std::istream& operator>>(std::istream& is, String& s);
public:
	String();
	String(const char* pstr);
	String(const String& rhs);
	String& operator=(const String& rhs);
	String& operator=(const char* pstr);
	String& operator+=(const String& rhs);
	String& operator+=(const char* pstr);
	char& operator[](std::size_t index); // 非const调用
	char& operator[](std::size_t index) const;// const对象调用
	std::size_t size()const;
	const char* c_str()const;
private:
	char* _pstr;
	
};
std::size_t String::size()const
{
	return strlen(this->_pstr);
}
const char* String::c_str()const
{
	return this->_pstr;
}
String::String() :_pstr(nullptr)  // 后面的操作需要判空
{
	cout << "String()" << endl;
}
String::String(const char* pstr) :_pstr(new char[strlen(pstr)+1]())
{
	strcpy(this->_pstr,pstr);
}

String::String(const String& rhs) :_pstr(new char[strlen(rhs._pstr) + 1])
{
	cout << "String(const String& rhs)" << endl;
	strcpy(this->_pstr, rhs._pstr);
}

String& String::operator=(const String& rhs)
{
	if (&rhs != this)
	{
		delete[] this->_pstr;
		this->_pstr = nullptr;
		this->_pstr = new char[strlen(rhs.c_str() + 1)]();
		strcpy(this->_pstr, rhs.c_str());
	}
	
	return *this;
}
String& String::operator=(const char* pstr)
{
	String tmp(pstr);
	*this = tmp;  // 调用String的operator=()函数。
	return tmp;
}
String& String::operator+=(const String& rhs)
{
	int len = this->size() + rhs.size() + 1;
	char* p = new char[len + 1] ();
	strcpy(p,this->c_str());
	strcat(p,rhs.c_str());
	delete[] this->_pstr;
	this->_pstr = p;
	return *this;
}
String& String::operator+=(const char* pstr)
{
	//char* p = new char[this->size()+strlen(pstr) + 1]();
	//strcpy(p, this->c_str());
	//strcat(p, pstr);
	//delete[] this->_pstr;
	//this->_pstr = p;
	String tmp(pstr);
	*this += tmp; // 调用operator+=(const String& rhs)
	return *this;
}
char& String::operator[](std::size_t index)
{
	if (index < this->size())
	{
		return this->_pstr[index];
	}
	else {
		static char nullchar = '\0';
		return nullchar;
	}
}
char& String::operator[](std::size_t index) const
{
	if (index < this->size())
	{
		return this->_pstr[index];
	}
	else {
		static char nullchar = '\0';
		return nullchar;
	}
}






bool operator==(const String& lhs, const String& rhs)
{
	return !strcmp(lhs.c_str(),rhs.c_str());
}
bool operator!=(const String& lhs, const String& rhs)
{
	return strcmp(lhs.c_str(), rhs.c_str());
}

bool operator>(const String& lhs, const String& rhs)
{
	return strcmp(lhs.c_str(),rhs.c_str());
}
bool operator<(const String& lhs, const String& rhs)
{
	return strcmp(lhs.c_str(), rhs.c_str());
}
bool operator<=(const String& lhs, const String& rhs)
{
	return strcmp(lhs.c_str(), rhs.c_str());
}
bool operator>=(const String& lhs, const String& rhs) 
{
	return strcmp(lhs.c_str(), rhs.c_str());
}

std::ostream& operator<<(std::ostream& os, const String& s)
{
	os << s.c_str();
}
std::istream& operator>>(std::istream& is, String& s)
{
	if (s._pstr)
	{
		delete s._pstr;
		s._pstr = nullptr;
	}
	std::vector<char> buffer;
	char ch;
	while ((ch = is.get()) != '\n')
	{
		buffer.push_back(ch);
	}
	s._pstr = new char[buffer.size() + 1]();
	strncpy(s._pstr,&buffer[0],buffer.size());
	return is;
}

http://www.kler.cn/a/449835.html

相关文章:

  • java web springboot
  • 环网冗余CAN转光纤 CAN光端机在风电项目应用
  • 写给Pythoner的前端进阶指南(五):事件驱动模型
  • LeetCode:1387. 将整数按权重排序(记忆化搜索 Java)
  • 【QSS样式表 - ⑥】:QPushButton控件样式
  • 差分矩阵(Difference Matrix)与累计和矩阵(Running Sum Matrix)的概念与应用:中英双语
  • ACl访问控制列表
  • 高校就业管理:系统设计与实现的全流程分析
  • 如何写好一份科技报告
  • Textual Dataset Distillation via Language Model Embedding
  • 计算机视觉技术未来发展趋势:创新与变革共舞
  • MHA binlog server
  • 代码随想录day22 | 回溯算法理论基础 leetcode 77.组合 77.组合 加剪枝操作 216.组合总和III 17.电话号码的字母组合
  • 【蓝碳】基于GEE云计算、多源遥感、高光谱遥感技术、InVEST模型、PLUS模型的蓝碳储量估算;红树林植被指数计算及提取
  • vue中的css深度选择器v-deep 配合!important
  • 【MySQL】MySQL 官方安装包形式
  • 日志以及MVCC
  • Linux(Ubuntu)命令大全——已分类整理,学习、查看更加方便直观!(2024年最新编制)
  • Linux Shell 脚本编程基础知识篇—shell 运算命令详解
  • Vue2四、 scoped样式冲突,data是一个函数,组件通信-父传子-子传父-非父子
  • 每天学习一个思维模型 - 直觉
  • 什么是根服务器?有什么作用?
  • 搜索引擎蜘蛛池的原理是什么,蜘蛛池搭建教程(蜘蛛池.中国)
  • 运维工程师面试系统监控与优化自动化与脚本云计算的理解虚拟化技术的优点和缺点
  • docker 安装openresty
  • CentOS7系统下部署tomcat,浏览器访问localhost:8080/