C++初阶学习——探索STL奥秘——模拟实现string类

news2024/9/29 21:21:00

1、string类的构造

上面的代码从表面看没什么问题,但是运行后会发现程序有多处bug 

 

但是如上图一样,这样改进依然有bug 

因为我们编写无参构造函数的时候,肯定要让_str默认为nullptr,但是这样的话,在main函数中创建对象s2并调用函数c_str,函数就会返回nullptr,无法打印,程序就会崩溃 

2.string的拷贝构造

如果没有建立拷贝构造函数,则在程序中有对象拷贝另一个对象的时候,就会调用系统默认的拷贝构造。默认的拷贝构造是浅拷贝,浅拷贝对程序的危害很大,极容易产生内存方面的问题

解决方法就是自己建立一个拷贝构造函数

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

3、string类的析构函数 

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

4、string类的运算符重载 

4.1operator=写法

4.1.1传统写法

4.1.2创新写法 

4.1.3简洁写法 

4.2operator>>写法 

初步的思路: 

但是会发现:

所以我们要调用istream&的函数get

我们要添加一个clear函数,这个clear可以清空原本对象的内容

		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}

但是都做到这一步了,还发现有bug 

最终,再次进行改进,解决以上的两个问题

4.3operator<<的写法 

为什么程序会运行错误呢?

主要有两点原因

解决方法:

整体代码(含有部分string类的函数):

#pragma once
#include<assert.h>
#include<stdio.h>
#include<string.h>
using namespace std;
namespace bit
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			memmove(_str, str, _size + 1);
		}
		string(const string& str)
		{
			_size = str._size;
			_capacity = str._capacity;
			_str = new char[_capacity + 1];
			memmove(_str, str._str, _size + 1);
		}
		~string()
		{
			if (_str != nullptr)
			{
				delete[] _str;
				_str = nullptr;
			}
			_capacity = 0;
			_size = 0;
		}
		const char* c_str()const
		{
			return this->_str;
		}
		size_t size()const
		{
			return _size;
		}
		const char& operator[](size_t pos)const
		{
			assert(pos < _size);
			return _str[pos];
		}
		char* begin()const
		{
			return _str;
		}
		char* end()const
		{
			return _str + _size;
		}
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tem = new char[n + 1];
				memmove(tem, _str, _size + 1);
				delete[] _str;
				_capacity = n;
				_str = tem;
			}
		}
		void insert(size_t pos, size_t n, const char c)
		{
			assert(pos <= _size);
			if (_size + n  > _capacity)
			{
				reserve(n + _size);
			}
			int end = (int)_size;
			while (end >= (int)pos)
			{
				_str[end + n] = _str[end];
				end--;
			}
			for (int i = n; i > 0; i--)
			{
				_str[pos + i - 1] = c;
			}
			_size += n;
		}
		void resize(size_t n, const char c='\0')
		{
			if (n > _size && n > _capacity)
			{
				reserve(n);
				int k = n - _size;
				for (int i = _size; i < _size + k; i++)
					{
						_str[i] = c;
					}
				_str[_size + k] = '\0';
				_capacity = n;
				_size = n;
			}
			if (n > _size && n < _capacity)
			{
				int k = n - _size;
				for (int i = _size; i < _size + k; i++)
				{
					_str[i] = c;
				}
				_str[_size+k] = '\0';
				_size = n;
			}
			if (n < _size && n < _capacity)
			{
				_str[n] = '\0';
				_size = n;
			}
		}
		void push_back(char c)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			_str[_size] = c;
			++_size;
			_str[_size] = '\0';
		}
		void append(const char* str)
		{
			int size = strlen(str);
			if (_size + size > _capacity)
			reserve(_size + size+1);
			memmove(_str + _size, str, size+1);
			_size += size;
		}
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator=(const string& str)
		{
			_size = str._size;
			_capacity = str._capacity;
			_str = new char[_capacity + 1];
			memmove(_str, str._str, _size + 1);
			return *this;
		}
		string& operator+=(const char* str)
		{
			append(str);
			return *this;
		}
		void erase(size_t pos, size_t len = (size_t)-1)
		{
			assert(pos <= _size);
			if (len == (size_t)-1||pos+len>_size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				int end = pos;
				while (end+len<=_size)
				{
					_str[end] = _str[end + len];
					end++;
				}
				_str[end] = '\0';
				_size -= len;
			}
		}
		size_t find(char ch, size_t pos = 0)
		{
			assert(pos <= _size);
			for (int i = pos; i <= _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return (size_t)-1;
		}
		size_t find(const char* str, size_t pos = 0)
		{
			assert(pos <= _size);
			const char* tem = strstr(_str + pos, str);
			if (tem)
			{
				return tem-_str;
			}
			else
			{
				return (size_t)-1;
			}
		}
		string substr(size_t pos = 0, size_t len = (size_t)-1)
		{
			assert(pos < _size);
			bit::string a;
			if (len == (size_t)-1||len+pos>_size)
			{
				a.reserve(_size - pos);
				a._capacity = _size - pos;
				for (int i = pos; i < _size; i++)
				{
					a += _str[i];
				}
			}
			else
			{
				a.reserve(len);
				a._capacity = len;
				for (int i = pos; i < pos + len; i++)
				{
					a += _str[i];
				}
			}
			a._size = len;
			return a;
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
		bool operator<(const bit::string& s) const
		{
			int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);
			return ret == 0 ? _size < s._size : ret < 0;
		}

		bool operator==(const bit::string& s) const
		{
			return _size == s._size&& memcmp(_str, s._str, _size) == 0;
		}

		bool operator<=(const bit::string& s) const
		{
			return *this < s || *this == s;
		}

		bool operator>(const bit::string& s) const
		{
			return !(*this <= s);
		}

		bool operator>=(const bit::string& s) const
		{
			return !(*this < s);
		}

		bool operator!=(const bit::string& s) const
		{
			return !(*this == s);
		}
		const static size_t npos = -1;
	private:
		size_t _size;
		size_t _capacity;
		char* _str;
	};
	ostream& operator<<(ostream& out, const bit::string& str)
	{
		for (auto s : str)
		{
			out << s;
		}
		return out;
	}
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch = in.get();
		while (ch == ' ' || ch == '\n')
		{
			ch = in.get();
		}
		char b[128];
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			b[i++] = ch;
			if (i == 127)
			{
				b[i] = '\0';
				s += b;
				i = 0;
			}
			ch = in.get();
		}
		if (i != 0)
		{
			b[i] = '\0';
			s += b;
		}
		return in;
	}
};

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

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

相关文章

使用npm全局安装typescript

查看npm安装 npm -v 安装typescript npm i -g typescript 查看安装 tsc 这就是标致着安装完成。

uBlock Origin很快将无法在Chrome上使用 开发者发布情况说明

Chrome v127 版开始扩展程序页面将自动显示即将不再支持的扩展程序&#xff0c;包括知名的广告拦截扩展程序 uBlock Origin 也在谷歌的警告列表中。昨天 uBO 团队发布新的支持文档对目前的情况进行说明&#xff0c;简单来说就是 Chrome 将不再支持基于 Manifest v2 开发的扩展程…

【设计模式入门】设计模式全解析:23种经典模式介绍与评级指南(设计师必备)

文章目录 设计模式简介引言七项基本原则创建型模式单例模式&#xff08;Singleton&#xff09;工厂方法模式&#xff08;Factory Method&#xff09;抽象工厂模式&#xff08;Abstract Factory&#xff09;建造者模式&#xff08;Builder&#xff09;原型模式&#xff08;Proto…

文件夹图标变白色无法打开:高效数据恢复指南

在日常使用电脑的过程中&#xff0c;我们可能会遇到一种令人困扰的情况——文件夹图标突然变成白色且无法正常打开。这一现象不仅影响了文件管理的便捷性&#xff0c;还可能意味着重要数据的丢失风险。本文将深入探讨这一现象的原因&#xff0c;并提供一种专业且高效的数据恢复…

一二三应用开发平台应用开发示例(11)——收藏夹功能高代码改造及总结

背景 前面使用低代码配置&#xff0c;把实体配置、库表和模式化的代码生成出来了&#xff0c;实际上是用平台帮忙开发人员把“体力活”给干了。接下来&#xff0c;就需要在此基础上进行个性化逻辑的开发。 文档收藏 完善实体模型 文档收藏夹我们原先配置了三个关键属性&…

【Mind+】掌控板入门教程04 迷你动画片

还记得小时候每天放学必看的动画片吗&#xff1f;还记得那些年陪伴我一起长大的卡通人物吗&#xff1f;勇救爷爷的葫芦娃&#xff0c;我们的朋友小哪吒&#xff0c;相信这些经典的动画形象已经成为了一代人童年的美好回忆。今天就让我们用掌控板来制作一部迷你动画片吧。 项目示…

stm32入门学习10-I2C和陀螺仪模块

&#xff08;一&#xff09;I2C通信 &#xff08;1&#xff09;通信方式 I2C是一种同步半双工的通信方式&#xff0c;同步指的是通信双方时钟为一个时钟&#xff0c;半双工指的是在同一时间只能进行接收数据或发送数据&#xff0c;其有一条时钟线&#xff08;SCL&#xff09;…

代码随想录——买卖股票的最佳时机 IV(Leetcode 188)

题目链接 动态规划 class Solution {public int maxProfit(int k, int[] prices) {int[][] dp new int[prices.length][2 * k 1];// 初始化for(int i 1; i < 2 * k 1; i i 2){dp[0][i] -prices[0];}// dp更新寻找最大利润for(int i 1; i < prices.length; i){…

使用Halcon变换与校正图像

使用Halcon变换与校正图像 文章目录 使用Halcon变换与校正图像1. 二维图像的平移、旋转和缩放1.图像的平移2.图像的旋转3.图像的缩放2. 图像的仿射变换3. 投影变换4 实例&#xff1a;透视形变图像校正 由于相机拍摄的时候可能存在角度偏差&#xff0c;因此实际获得的画面可能会…

(C23/C++23) 语句末尾的标签

文章目录 &#x1f516;前言&#x1f3f7;️ref&#x1f3f7;️标号 &#x1f516;兼容&#x1f3f7;️23标准前&#x1f3f7;️23标准后&#x1f3f7;️原因 &#x1f516;未兼容&#x1f516;END&#x1f31f;关注我 &#x1f516;前言 &#x1f3f7;️ref C23提案复合语句末…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 两数之和绝对值最小(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题…

基于机器学习和深度学习的时间序列分析和预测(Python)

时间序列数据与其它数据不同主要是因为时间序列数据在时间维度上存在依赖关系&#xff0c;这说明在时间序列数据当中过去的历史数据当中隐藏着一些时间序列数据固有的特性&#xff0c;例如&#xff0c;周期性、趋势性、不规则性等。时间序列预测便是通过不同的方法来捕捉这种规…

【抽象工厂模式】从理论到实战:构建可扩展的软件家族(设计模式系列)

文章目录 Java设计模式系列&#xff1a;抽象工厂模式详解1. 引言抽象工厂模式概述为何选择抽象工厂模式 2. 基础知识回顾Java基础概念复习面向对象编程原则设计模式的原则和目的 3. 抽象工厂模式的定义定义与解释模式的目的与其他工厂模式的区别 4. 抽象工厂模式的结构抽象产品…

【Android】数据持久化——数据存储

持久化技术简介 在你打开完成了一份PPT之后关闭程序&#xff0c;再次打开肯定是希望之前的内容还存在在电脑上&#xff0c;一打开PPT&#xff0c;之前的内容就自动出现了。数据持久化就是将那些内存中的瞬时数据保存到存储设备中&#xff0c;保证即使在手机或电脑关机的情况下…

React 学习——别名路径配置(可以使用@代表src),引用文件时使用;联想路径提示

一.别名路径配置 1、安装craco &#xff08;npm i -D craco/craco&#xff09;&#xff1b;安装成功的截图如下&#xff1a; 2、在项目的根目录下创建一个 名为 craco.config.js 文件&#xff1b;&#xff08;必须是根目录下&#xff0c;名称必须和我这个一样&#xff09;&…

C语言调试宏全面总结(六大板块)

C语言调试宏进阶篇&#xff1a;实用指南与案例解析C语言调试宏高级技巧与最佳实践C语言调试宏的深度探索与性能考量C语言调试宏在嵌入式系统中的应用与挑战C语言调试宏在多线程环境中的应用与策略C语言调试宏在并发编程中的高级应用 C语言调试宏进阶篇&#xff1a;实用指南与案…

嵌入式人工智能(44-基于树莓派4B的扩展板-LED按键数码管TM1638)

树莓派性能非常强悍&#xff0c;但是对于某些复杂的项目来说&#xff0c;会出现心有余而口不足的情况&#xff0c;为了解决这类问题&#xff0c;可以在树莓派上使用扩展板&#xff0c;我们介绍几款常见的扩展板&#xff0c;不仅可以扩展到树莓派&#xff0c;其他单片机或嵌入式…

Vue3 列表自动滚动播放(表头固定、列表内容自动滚动播放)+ vue3-seamless-scroll - 附完整示例

vue3-seamless-scroll&#xff1a;Vue3.0 无缝滚动组件&#xff0c;支持Vite2.0&#xff0c;支持服务端打包 目前组件支持上下左右无缝滚动&#xff0c;单步滚动&#xff0c;并且支持复杂图标的无缝滚动&#xff0c;目前组件支持平台与Vue3.0支持平台一致。 目录 效果 一、介绍…

安装vscode -- linux

前言 相信很多人在刚开始使用linux时&#xff0c;不知道怎么安装vscode来辅助我们编程&#xff0c;那么我将在此记录我所用的安装vscode的方法。 安装方法 方法一&#xff1a;snap 第一步&#xff1a;检查软件更新状况 sudo apt update在终端输入上述命令&#xff0c;会提…

大模型学习笔记 - LLM 之RLHF人类对齐的简单总结

LLM - RLHF人类对齐的简单总结 LLM-人类对齐 1. RLHF(Reinforcement Learning from Human Feedback, RLHF),基于人类反馈的强化学习2 奖励模型训练3 强化学习训练 3.1 PPO介绍3.2 进阶的RLHF的介绍 3.2.1. 过程监督奖励模型3.2.2. 基于AI反馈的强化学习3.2.3. 非强化学习的对齐…