string的模拟实现与深浅拷贝

news2024/11/15 9:45:04

在上一章中可以看见,string类函数的基本实现和用法,在本文。来用基础的语言来模拟实现string类,来了解一下他们的基础底层;

在VS中string,我们可以看见,实现VS的类成员很多,很麻烦;

 我们自己实现为了基础理解底层时,可以把成员设的简单点;只设 char*  size  和 capacity

在实现一些成员函数时

注意事项:

防止权限扩大

要根据string函数的具体要求去实现,不要忘了实现const类型,防止权限扩大;

注意只是两个接口;一个可读可写的[ ],一个只能读的不能写的[ ]。

string输入流

std::cin 的输入 ,自动会将 空格(’ ‘) ,等认为换行符;这样在实现,string的输入流时,会导致无法输入 像we are famliy 的字符;如此就要请出 getline,这个可以自己实现换行符 是什么的std函数。 

深浅拷贝问题

因此,这里要记得为string写深拷贝,编译器自己实现的浅拷贝无法实现;

增加扩容效率

以substr为例子,可以选择直接 += 但这样会导致经常扩容,效率低;但这里能提前知道了内存大小,可以提前扩容,增加效率 

隐式类型转换

因为 _size  的类型是size 无 符号,如果将end设为int类型,如果情况是pos = 0,在减到 - 1时 进行类似类型转换,int 转为 size_t ;-1 无符号的反义码是11111111 11111111 很大;导致无限循环;

或者 换一个 循环 不访问 -1 的也行; 但最好保证类型一致;

字符串 最后存在“ \0 ”

字符串最后的"\0"存在 ,可以移动过去,要注意;

对这里提醒一下,对于这种移动数据的插入,最好少用,效率太低了,注意尽量少用,虽然很方便

    注意域限定:

海滩std的模板函数 swap 

但要注意这个std::swap,虽然存在模板,可以任意转换但是,转换中却有拷贝构造,和运算符重载,效率很低;但是方便也是确实的

参考代码

string.h 

#pragma once

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
//#include<string>
#include<assert.h>
using namespace std;

namespace xryq {

	class string {
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}
		const_iterator end() const
		{
			return _str + _size;
		}

		//string()
		//	:_str(new char[1]{ '\0' })
		//	,_size(0)
		//	,_capacity(0)
		//{}



		string(const string& s)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_capacity = s._capacity;
			_size = s._size;
		}


		//现代写法
		string(const string& s)
		{
			string tmp(s._str);
			swap(s); 
		}
		//构造函数重载
		//string(const char* str = '\0')
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		~string()
		{
			delete[] _str;
			_size = _capacity = 0;
		}
		


		const char& operator[](size_t pos) const
		{
			assert(pos < _size);

			return _str[pos];
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);

			return _str[pos];
		}



		const char* c_str() const
		{
			return _str;
		}

		const size_t capacity() const
		{
			return _capacity;
		}

		const size_t size() const 
		{
			return _size;
		}



		void clear()
		{
			//编译器 遇到 \0 就失效 在前面加 \0相当于清除
			_str[0] = '\0';
			//_capacity = _size = 0;
			//容量没有清 只是  数量变了
			_size = 0;
		}




		void swap(string s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		
		// 现代写法
		string& operator=(const string s)
		{
			if (this != &s)
			{
				swap(s);
				return *this;
			}
		}

		//末代写法
		//string& operator=(const string& s)
		//{
		//	if (this != &s)
		//	{		
		//		//这里先清除的主要原因是  更方便 且不会有内容浪费  等问题
		//		delete[] _str;
		//		_str = new char[s._capacity + 1];
		//		_capacity = s._capacity;
		//		_size = s._size;
		//	}
		//}

		void reserve(size_t n);
		void push_back(char ch);
		void append(const char* str);
		string& operator+=(char ch);
		string& operator+=(const char* str);

		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void erase(size_t pos, size_t len = npos);

		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);
		string substr(size_t pos = 0, size_t len = npos);

		//static const size_t npos = -1;  这里可以 或者 只能看成 c++ 对 整形的绿色通道
		//static const double i = 1.1;  只有整形不报错
		
	private:
		char* _str;
		size_t _size;
		size_t _capacity;

		static const size_t npos = -1;
	};


	void text_string1();
	void text_string2();


	bool operator<(const string& s1, const string& s2);
	bool operator<=(const string& s1, const string& s2);
	bool operator>(const string& s1, const string& s2);
	bool operator>=(const string& s1, const string& s2);
	bool operator==(const string& s1, const string& s2);
	bool operator!=(const string& s1, const string& s2);

	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);

	
}

string.cpp


#include"string.h"

namespace xryq{
	//static const size_t npos = -1;

	void string::reserve(size_t n)
	{
		assert(n > _capacity);
		cout << n << endl;
		char* tmp = new char[n + 1];
		_capacity = n;
		strcpy(tmp, _str);
		_str = tmp;
	}

	void string::push_back(char ch)
	{
		if (_capacity == _size)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		_str[_size] = ch;
		_size++;
	}
	string& string::operator+=(char ch)
	{
		push_back(ch);
		return *this;
	}

	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}
	void string::append(const char* str)
	{
		size_t len = strlen(str);
		if(_size + len > _capacity)
		reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);

		strcpy(_str + _size, str);
		_size += len;
	}

	void string::insert(size_t pos, char ch)
	{
		assert(pos <= _size);

		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : _capacity * 2);
		}
		size_t end = _size;
		//int end = _size + 1;
		//这是c语言 留下来的一个坑;如果比较时 类型不一样那么就会 
		//进行隐式类型转换   小向大 的转换  int 向 unsign的转换
		while (end >= pos)
		{
			_str[end + 1] = _str[end];
			--end;
		}
		_str[end] = ch;
		++_size;
		//或者 不访问-1也许
		//while (end > pos)
		//{
		//	_str[end] = _str[end - 1];
		//	--end;
		//}
		//_str[end] = ch;
		//++_size;
	}


	void string::insert(size_t pos, const char* str)
	{
		assert(pos <= _size);
		size_t len = strlen(str);
		if (_size + len > _capacity)
		{
			reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);
		}

		size_t end = _size + len;
		while (end > pos + len - 1)
		{
			_str[end] = _str[end - len];
			--end;
		}

		for (int i = 0; i < len; ++i)
		{
			_str[pos + i] = str[i];
		}
		_size += len;
	}

	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (len >= _size - pos)
		{

			_str[pos] = '\0';
			_size = pos;
		}
		else {
			//for (size_t i = 0; i < _size - pos - 1 - len; ++i)
			//{
			//	_str[pos + i] = _str[pos + len + i];
			//}
			//_str[_size - 1 - len] = '\0';
			//最后一个字符是\0
			for (size_t i = 0; i <= _size - pos - len; ++i)
			{
				_str[pos + i] = _str[pos + len + i];
			}
			_size -= len;
		}
	}

	size_t string::find(char ch, size_t pos)
	{
		assert(pos < _size);

		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}

		return npos;
	}

	size_t string::find(const char* str, size_t pos)
	{
		assert(pos < _size);

		const char* ch = strstr(_str, str);
		for (size_t i = pos; i < _size; ++i)
		{
			if (_str[i] = *ch)
			{
				return i;
			}
		}
		return npos;
	}

	string string::substr(size_t pos, size_t len)
	{
		assert(pos < _size);
		string tmp;
		if (_size - pos <= len)
		{
			len = _size - pos;
		}
		//提前算好空间 提高效率
		tmp.reserve(len);
		for (size_t i = 0; i <= len; ++i)
		{
			tmp += _str[i + pos];
		}
		return tmp;
	}

	ostream& operator<<(ostream& out, const string& s)
	{

		for (auto i : s)
		{
			out << i;
		}
		//cout << s.c_str();

		return out;
	}

	istream& operator>>(istream& in, string& s)
	{
		s.clear();

		char ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			s += ch;

			ch = in.get();
		}

		return in;
	}
	//上面的牵扯到 多次扩容  效率比较低

	//istream& operator>>(istream& in, string& s)
	//{
	//	s.clear();
	//	char ch;
	//	const int N = 256;
	//	char buff[N];
	//	int i = 0;
	//	ch = in.get();
	//	while (ch != ' ' && ch != '\n')
	//	{
	//		buff[i] = ch;
	//		i++;
	//		if (i == N - 1)
	//		{
	//			buff[i] = '\0';
	//			s += buff;
	//			i = 0;
	//		}
	//		ch = in.get();
	//	}
	//	if (i > 0)
	//	{
	//		buff[i] = '\0';
	//		s += buff;
	//	}

	//	return in;
	//}



}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2082217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI写作|AI底层方法论第三节-AI常用的格式(作用+案例)

本文背景: hello大家好我是大象&#xff0c;直接接上文&#xff0c;这一篇我们讲AI的常用格式&#xff0c;这一节也是基础课中非常重要的一个内容&#xff0c;有了正确的格式不仅能输出我们想要的文章内容&#xff08;按格式&#xff09;让AI清楚的知道,哪些是要求,哪些是任务。…

CSS系列之浮动清除clear(三)

一、为什么需要清除浮动 浮动的原理是让元素脱离文档流&#xff0c;直接浮在桌面上。使用浮动后续添加内容布局可能会产生布局混乱&#xff0c;造成高度坍塌&#xff0c;这时候就可以利用清除浮动来解决父元素高度塌陷的问题。 <!DOCTYPE html> <html lang"en&q…

K8S对接Ceph分布式存储

文章目录 一、Ceph理论知识1、Ceph简介2、Ceph分布式存储的优点3、Ceph核心组件 二、部署Ceph高可用集群1、服务器环境信息2、部署前环境准备工作3、部署Ceph监控服务Monitor4、激活Ceph存储服务OSD 三、K8S对接Ceph存储1、K8S对接Ceph RBD实现数据持久化2、基于Ceph RBD生成PV…

脚本加密解密

shell脚本是维护Linux系统的一个必不可少的工具&#xff0c;简单、便捷、可以执行强。 但是shell脚本内会存储一些隐私信息&#xff08;如系统账号、密码&#xff0c;应用程序账号、密码&#xff0c;IP&#xff0c;数据存放路径等等&#xff09;&#xff0c;以明文的形式存放&…

报表融合大屏,做不一样的财务分析!

冷冰冰的数据如何让人眼前一亮&#xff1f; 千篇一律的表格如何让数据可视化&#xff1f; ...... 赶快丢掉那些传统的表格工具吧&#xff01;&#xff01;&#xff01;现在我们都用更智能的工具来做报表了&#xff01; 财务报表是什么&#xff1f; 财务报表是企业财务状况、…

深度学习-OpenCV运用(1)

文章目录 一、OpenCV介绍二、OpenCV运用1.读取保存图片2.读取视频3.图像切片 一、OpenCV介绍 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;它主要用于实时的图像处理和计算机视觉任务。虽然OpenCV本…

【STM32】FSMC

FSMC在正点原子的HAL课程中用法较为单一&#xff0c;就是用来模拟8080时序驱动LCD屏幕&#xff0c;其实就是利用FSMC读写LCD模块的SRAM。当然&#xff0c;这个我也没有买&#xff0c;只学习了理论。 大部分图片来源&#xff1a;正点原子HAL库课程 专栏目录&#xff1a;记录自己…

无线通信-WIFI通信

文章目录 1. 基础知识2. 工作模式3. AT指令4. 常用AT指令实例5. 连接原子云6. 使用usb转ttl模块测试ATK-MW8266D7. 使用STM32F103ZET6战舰开发板透传模式8. 使用STM32F103ZET6战舰板连接原子云 1. 基础知识 ATK-ESP-01 ATK-ESP-01模块支持标准的IEEE802.11b/g/n协议&#xff0c…

scriptlet failed, exit status 1

执行命令&#xff1a;rpm -evh percona-release-1.0-29.noarch 报错信息&#xff1a; mv: cannot stat ‘/etc/yum.repos.d/percona-telemetry-release.repo’: No such file or directory error: %preun(percona-release-1.0-29.noarch) scriptlet failed, exit status 1 …

面试必备!15个SSH服务器经典问题,助你轻松过关斩将!

SSH(Secure Shell)是Linux系统中最常用的远程管理工具之一&#xff0c;掌握它是每个运维工程师的必备技能。在面试中&#xff0c;关于SSH服务器的相关问题经常会被问到。本文将列出15个常见的SSH服务器面试题&#xff0c;并提供简要解答&#xff0c;帮助你在面试中脱颖而出。 什…

使用 Puppeteer 在 PHP 中解决 reCAPTCHA 以进行网页抓取

您是否在抓取数据时遇到 reCAPTCHA 障碍&#xff1f;我也遇到过。这些 CAPTCHA 挑战会将简单的抓取任务变成一大障碍。但别担心&#xff0c;我有一个解决方案可以帮助您轻松绕过这些障碍。 在本博文中&#xff0c;我将引导您使用 Puppeteer&#xff08;一个功能强大的 Node.js…

【Java设计模式】Bridge模式:在Java中解耦抽象与实现

文章目录 【Java设计模式】Bridge模式&#xff1a;在Java中解耦抽象与实现一、概述二、Bridge设计模式的别名三、Bridge设计模式的意图四、Bridge模式的详细解释及实际示例五、Java中Bridge模式的编程示例六、Bridge模式类图七、Java中何时使用Bridge模式八、Java中Bridge模式的…

如何使用ssm实现毕业生交流学习平台+vue

TOC ssm306毕业生交流学习平台vue 绪论 1.1 研究背景 现在大家正处于互联网加的时代&#xff0c;这个时代它就是一个信息内容无比丰富&#xff0c;信息处理与管理变得越加高效的网络化的时代&#xff0c;这个时代让大家的生活不仅变得更加地便利化&#xff0c;也让时间变得…

某系统任意用户创建漏洞

初来人间不知苦&#xff0c;潦倒半生一身无&#xff0c;转身回望来时路&#xff0c;方知生时为何哭。 漏洞描述 某系统存在任意用户创建漏洞&#xff0c;发送特定的请求包攻击者可以创建管理员账户登录后台 漏洞实战 出现漏洞的文件为 userproce.php&#xff0c;出现漏洞的…

汽车免拆诊断案例 | 马自达CX-3无音频输出

故障现象&#xff1a; 使用触摸屏打开收音机时&#xff0c;单选按钮打开收音机&#xff0c;但无法访问菜单。使用中控台中的旋转控制旋钮时&#xff0c;也会遇到相同的情况。 没有音频输出到车上的任何扬声器&#xff0c;包括卫星导航、蓝牙或语音识别。音量调节也不起作用&a…

食家巷大烤馍,美味超实在

在美食的世界里&#xff0c;总有一些味道能勾起我们内心深处的温暖回忆&#xff0c;食家巷大烤馍便是其中之一。 每一个食家巷大烤馍都是匠心的结晶。首先&#xff0c;精选优质的面粉&#xff0c;确保了烤馍的基础品质。这些面粉经过严格的筛选&#xff0c;颗粒细腻&#xff0c…

2024/8/28 英语每日一段

“Its great were getting these investments, but you actually cant materialize the benefits of these investments if the cities actually cant afford to run it,” he said. All of the eight cities say the planned expansions, such as new light rail lines in Ott…

掌握高效管理技巧:9款顶级待办事项软件

本文将介绍9款优质待办事项清单工具&#xff1a;1.PingCode&#xff1b;2.Worktile&#xff1b;3.滴答清单 (TickTick)&#xff1b;4.日事清&#xff1b;5.效能工作任务&#xff1b;6.印象笔记&#xff1b;7.MyLifeOrganized&#xff1b;8.Quire&#xff1b;9.OmniFocus。 在当…

CTFhub通关攻略-SSRF篇【1-5关】

01关 内网访问 根据题意&#xff0c;它让我们去尝试访问127.0.0.1的flag.php&#xff0c;我们点进题目链接 有一个url参数可以进行输入&#xff0c;我们直接访问127.0.0.1的flag.php 这样就得到了flag 02 伪协议读取文件 点开题目链接发现有一个url的参数可以进行填写 题中说让…

【贪心 决策包容性 】757. 设置交集大小至少为2

本文涉及知识点 贪心 决策包容性 LeetCode757. 设置交集大小至少为2 给你一个二维整数数组 intervals &#xff0c;其中 intervals[i] [starti, endi] 表示从 starti 到 endi 的所有整数&#xff0c;包括 starti 和 endi 。 包含集合 是一个名为 nums 的数组&#xff0c;并…