STL —— string(终)

news2025/7/18 23:26:55

目录

1. swap() 函数的模拟实现

2. find() 函数的模拟实现

3. substr() 函数的模拟实现 

4. operator==()的重载模拟实现

5. << 和 >> 重载的模拟实现

6. getline() 的重载

7. 拷贝构造的现代写法

8. 赋值重载的现代写法


本片文章还是主要讲解 string 类中剩余几个函数的模拟实现:

1. swap() 函数的模拟实现

在C++库中就有swap()函数的实现,但是为什么要在string类中也要实现一个swap()函数呢?

我们可以先看一下库中的实现逻辑:

template <class T> void swap ( T& a, T& b )
{
  T c(a); a=b; b=c;
}

这里可以看到如果对内置类型,它会调用一次 拷贝构造、两次赋值重载、一次析构,而且都是深拷贝,这样的效率就会大大增加,虽然可以实现swap()的功能,但是一般不推荐使用,所以会在库中自己实现。

因此我们可以自己实现一个 swap() 函数,只要对内置类型进行交换即可:

void swap(string& str)
{
    std::swap(_str, str._str);
	std::swap(_size, str._size);
	std::swap(_capacity, str._capacity);
}

 除此之外,为了防止调用算法库的swap(),我们可以写一个全局的swap():

void swap(string& x, string& y)
{
	x.swap(y);
}

2. find() 函数的模拟实现

查找字符的模拟实现:

size_t find(char ch, size_t pos = 0) const
{
	for (size_t i = pos; i < _size; ++i)
	{
		if (_str[i] == ch)
		{
			return i;
		}
		else
		{
			return npos;
		}
	}
}

查找字符串的模拟实现,可以用strstr()函数来完成,查找成功strstr会返回查询到的位置的指针, 查找失败则会返回空,因此要两个指针相减得到下标:

size_t find(const char* ch, size_t pos = 0) const
{
	// 字符串匹配
	const char* p = strstr(_str, ch);
	if (p)
	{
		return p - _str;
	}
	else
	{
		return npos;
	}

}

3. substr() 函数的模拟实现 

取子串的操作从pos位置开始,取len个,代码如下:

string substr(size_t pos = 0, size_t len = npos)
{
	string sub;
	if (len >= _size - pos)
	{
		for (size_t i = pos; i < _size; ++i)
		{
			sub += _str[i];
		}
	}
	else
	{
		for (size_t i = pos; i < pos + len; ++i)
		{
			sub += _str[i];
		}
	}
	return sub;
}

4. operator==()的重载模拟实现

这里就只实现==的重载,其他的重载只需要复用即可。

d31b517f14da4c5999e306d3f90318de.png

在库中重载是在全局中实现的,主要是为了实现 const char* 和 string 类型的比较,这里模拟实现就不在全局中实现了:

bool operator==(const string& s)
{
	int ret = strcmp(_str, s._str);
	return ret == 0;
}

5. << 和 >> 重载的模拟实现

<< 的重载比较简单,注意重载成全局的就可以了:

ostream& operator<<(ostream& _out, const string& str)
{
    for (size_t i = 0; i < str.size(); ++i)
    {
		_out << str[i] << " ";
	}
	_out << endl;
	return _out;
}

cin 读不到' '或者'\n',要用get()获取

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

		char ch;
		//in >> ch;
		ch = in.get();
		char buff[128];
		size_t i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			// [0,126]
			if (i == 127)
			{
				buff[127] = '\0';
				s += buff;
				i = 0;
			}

			ch = in.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}

6. getline() 的重载

和>>类似:

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

		char ch;
		//in >> ch;
		ch = in.get();
		char buff[128];
		size_t i = 0;
		while (ch != '\n')
		{
			buff[i++] = ch;
			// [0,126]
			if (i == 127)
			{
				buff[127] = '\0';
				s += buff;
				i = 0;
			}

			ch = in.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}

7. 拷贝构造的现代写法

这个是拷贝构造的正常的写法:

  • 先动态开辟一块内存,并把str._str中的数据拷贝到其中;
  • 让_str指向ch指向的空间
  • _size 和 _capacity 分别赋值
string(const string& str)
{
	char* ch = new char[str._capacity + 1];
	strcpy(ch, str._str);
	_str = ch;
	_size = str._size;
	_capacity = str._capacity;
}

现代写法:

  • 新建一个tmp对象用str._str初始化;
  • 然后再和this进行交换就可以了。
string(const string& str)
{
	string tmp(str._str);
	swap(tmp);
}

8. 赋值重载的现代写法

这个是赋值重载的正常的写法:

  • 新构建一块空间并把str中的值拷贝到其中;
  • 释放掉this->_str指向的空间;
  • 让this->str 指向这块空间;
  • 给this->_size 和 this->_capacity 赋值
string& operator=(const string& str)
{
	if (this != &str)
	{
		_size = str._size;
		_capacity = str._capacity;
		char* tmp = new char[_capacity + 1];
		delete[] _str;
		strcpy(tmp, str._str);
		_str = tmp;
	}

	return *this;
}

现代写法:

  • 新建一个tmp对象用str拷贝构造;
  • this和tmp进行交换;
  • 因为局部变量出作用域会自动调用析构函数,所以这里不需要自己重新写一份delete[] tmp._str 释放掉this原来指向的空间,如果写了delete,记得把tmp._str 制空;
string& operator=(const string& str)
{
	string tmp(str);
	swap(tmp);
	return *this;
}

还有更简单的写法:

因为这里是传值传参,会自动调用拷贝构造,就不需要我们自己手动写一个tmp的拷贝构造了。

string& operator=(string str)
{
	swap(str);
	return *this;
}

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

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

相关文章

运维经验|Linux虚拟机如何挂载磁盘

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注、&#x…

路径规划——搜索算法详解(五):Dynamic A Star(D*)算法详解与Matlab代码

昨天休息了一天&#xff0c;今天继续学习搜索算法&#xff01;前几天已经分别介绍了Dijkstra算法、Floyd算法、RRT算法、A*算法&#xff0c;无独有偶&#xff0c;上述算法都只适用于静态环境下两点规划的场景&#xff0c;但是大部分场景是实时变化的&#xff0c;这对规划算法提…

二叉树的深度优先遍历(前中后)

1. 前序遍历 前序遍历是先输出根节点&#xff0c;再输出左子树&#xff0c;最后输出右子树。 2. 中序遍历 中序遍历&#xff0c;左子树&#xff0c;根节点&#xff0c;右子树 3. 后序遍历 左子树&#xff0c;右子树&#xff0c;根节点 4. 代码实现&#xff08;递归形式&…

Vulnhub:BROKEN: GALLERY

目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb WEB wen信息收集 目录扫描 进制转换 ssh登录 提权 信息收集 1、arp ┌──(root㉿ru)-[~/kali/vulnhub] └─# arp-scan -l Interface: eth0, type: EN10MB, M…

向量点乘有哪些作用呢

如下&#xff1a; 1.找到两个向量之间的夹角(不用多说) 2.求一个向量投影在另一个向量的投影&#xff1a; 我们把图中b的在a上的投影向量称作b1吧&#xff0c;因为b1就在a上&#xff0c;所以只需要求出b1的大小&#xff0c;然后乘以a的单位向量&#xff0c;我们就得到向量b1了…

Bezier曲线

1. 实验要求 2. Bezier曲线的原理 以及 公式推导 参考贝塞尔曲线&#xff08;Bezier Curve&#xff09;原理及公式推导_bezier曲线-CSDN博客 Bezier曲线的一些特性&#xff1a; 使用n个控制点来控制曲线形状 曲线通过起始点和终止点&#xff0c;接近但不通过中间点 2.1 直观…

结构化绑定optional(C++基础)

结构化绑定 处理多个返回值的操作&#xff1a;C17提出 之前多返回值喜欢用struct来返回。现在会做成元组&#xff0c;下图中设置C17的版本&#xff0c;不要设置错为C语言标准。 #include<iostream> #include<string> #include<tuple> std::pair<std::st…

ubuntu下给不同串口设置别名

目录 一、绑定设备ID 1.查看设备ID 2.编写usev规则 3.重新加载usev规则 4.查看 二、绑定USB端口号 1.先插入一个串口&#xff0c;查看USB设备信息 2.查看USB转串口信息 3.编写usev规则 4.重新加载usev规则 5.查看 在Ubuntu环境下&#xff0c;有时候工控机或者arm开…

新增收货地址

目录 &#x1f9c2;1.创建controller层 &#x1f953;2.创建service层 &#x1f32d;3.注意细节 &#x1f37f;4.避免dao数据暴漏 1.创建controller层 controller不做逻辑操作&#xff0c;只接受前端的数据 1.添加Api设置swagger模块名称2.RestController以json形式返回…

CAJViewer8.1下载地址及安装教程

CAJViewer是中国学术期刊&#xff08;CAJ&#xff09;全文数据库的专用阅读软件。CAJViewer是中国知识资源总库&#xff08;CNKI&#xff09;开发的一款软件&#xff0c;旨在方便用户在线阅读和下载CAJ数据库中的学术论文、期刊和会议论文等文献资源。 CAJViewer具有直观的界面…

2000-2021年各省技术市场发展水平数据(原始数据+计算结果)

2000-2021年各省技术市场发展水平数据&#xff08;原始数据计算结果&#xff09; 1、时间&#xff1a;2000-2021年 2、来源&#xff1a;国家统计局、统计年鉴 3、范围&#xff1a;30省 4、指标&#xff1a;技术市场成交额、国内生产总值、技术市场发展水平 5、计算说明“技…

java字符串(一)-- 字符串API,StringBuffer 和 StringBuilder,Object

String字符串相关的类 String的特性 String类&#xff1a;代表字符串。Java 程序中的所有字符串字面值&#xff08;如"abc" &#xff09;都作为此类的实例实现。String类是引用数据类型。 在 Java 8 中&#xff0c;String 内部使用 char 数组存储数据。 public fi…

C++的入门学习

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一、C关键字(C98) 二、命名空间 2.1 引入 ​编辑2.2 命名空间定义 2.3 命名空间的使用 三. C输入&输出 四.缺省参数 4.1 缺省参数概念 4.2 缺省参数分类 1.全缺省参数 2…

MCGS学习——水位控制

要求 插入一个水罐&#xff0c;液位最大值为37插入一个滑动输入器&#xff0c;用来调节水罐水位&#xff0c;滑动输入器最大调节为液位最大值&#xff0c;并能清楚的显示出液位情况用仪表显示水位变化情况&#xff0c;仪表最大显示设置直观清楚方便读数&#xff0c;主划线为小…

基于spark的大数据分析预测地震受灾情况的系统设计

基于spark的大数据分析预测地震受灾情况的系统设计 在本篇博客中,我们将介绍如何使用Apache Spark框架进行地震受灾情况的预测。我们将结合数据分析、特征工程、模型训练和评估等步骤,最终建立一个预测模型来预测地震造成的破坏程度,同时使用可视化大屏的方式展示数据的分布…

提升 RAG 效果的实践

提升 RAG 效果的实践 0. 引言1. 测试数据2. cohere/embed-multilingual-v3.0 的几组测试结果2-1. 第1组测试2-2. 第2组测试 3. BAAI/bge-m3 的几组测试结果3-1. 第1组测试 0. 引言 AI 大语言模型的主要应用方式之一就是 RAG&#xff0c;接下来计划陆续分享工作中提升 RAG 效果…

vue3封装Element表格

配置表头配置多选配置序号自定义操作列按钮 封装表格 Table.vue <template><el-table:data"tableData"width"100%":maxHeight"maxHeight"v-bind"$attrs"selection-change"handleSelectChange"row-click"hand…

考研数学|听完一遍汤家凤基础,1800都没思路,怎么办?

看了我这篇回答&#xff0c;保证你可以顺利的做1800题&#xff01; 如果你听了汤家凤老师的课&#xff0c;但是做题没思路&#xff0c;请不要担心&#xff0c;也不要急着换老师&#xff0c;你很有可能是方法错了。 请你反思一下&#xff1a; 1、你是不是听完课立刻就去做题。…

linux系统基础命令

1、Linux中文件的权限包括哪些&#xff1f;某个文件的权限列为644代表该文件属主、属组和其它用户分别有什么权限&#xff1f; 1&#xff09;Linux中文件的权限包括哪些&#xff1f; 在Linux系统中&#xff0c;文件的权限包括读取&#xff08;r&#xff09;、写入&#xff08;w…

ARP类型

地址解析协议ARP即可实现将IP地址解析为MAC地址 动态ARP 动态ARP表项由ARP协议通过ARP报文自动生成和维护&#xff0c;可以被老化&#xff0c;可以被新的ARP报文更新&#xff0c;也可以被静态ARP表项覆盖。 动态ARP适用于拓扑结构复杂、通信实时性要求高的网络。 静态ARP …