【C++教程从0到1入门编程】第八篇:STL中string类的模拟实现

一、 string类的模拟实现

下面是一个列子
#include <iostream>
namespace y
{class string{public: //string()            //无参构造函数//	:_str(nullptr)//{}//string(char* str)  //有参构造函数//	:_str(str)//{}string():_str(new char[1]){_str[0] = '\0';}string(char* str)   //构造函数在堆上开辟一段strlen+1的空间+1是c_str:_str(new char[strlen(str)+1]){strcpy(_str, str); //strcpy会拷贝\0过去}//string(char* str="")   //构造函数在堆上开辟一段strlen+1的空间+1是c_str//	:_str(new char[strlen(str) + 1])//{//	strcpy(_str, str); //strcpy会拷贝\0过去//}size_t size(){return strlen(_str);}bool empty(){return _str == nullptr;}char& operator[](size_t i)  //用引用返回不仅可以读字符,还可以修改字符{return _str[i];}~string()          //析构函数{if (_str){delete[] _str;_str = nullptr;}}const char* c_str() //返回C的格式字符串{return _str;}private:char* _str;};void TestString1(){string s1("hello");string s2;for (size_t i = 0; i < s1.size(); i++){s1[i] += 1;std::cout << s1[i] << " ";}std::cout << std::endl;for (size_t i = 0; i < s2.size(); i++){s2[i] += 1;std::cout << s2[i] << " ";}std::cout << std::endl;}void TestString2(){string s1("hello");string s2(s1);std::cout << s1.c_str() << std::endl;std::cout << s2.c_str() << std::endl;string s3("world");s1 = s3; //调试点这里,析构也是两次std::cout << s1.c_str() << std::endl;std::cout << s3.c_str() << std::endl;}
}

这段代码中,存在一定的问题,当我们调试时会发现!

默认的拷贝的构造函数出现的问题!

默认的赋值运算符重载出现的问题。!

        上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

此时引出了概念浅拷贝,

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。

那么深拷贝呢?

二、string类的模拟实现

头文件代码:

#include<iostream>
#include<assert.h>
namespace yyw
{class string{public:typedef char* iterator;public:string(const char* str = "")        //构造函数{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}//string s2(s1)string(const string& s):_str(nullptr), _size(0), _capacity(0){string tmp(s._str);this->swap(tmp);}//s1=s3string& operator=(const string& s) //(string s){//this->swap(s);string tmp(s._str);this->swap(tmp);return *this;}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}~string()                         //析构函数{if (_str){delete[] _str;_size = _capacity = 0;_str = nullptr;}}//string(const string& s)   //拷贝构造void push_back(char ch)           //增加字符{if (_size == _capacity)      //增加空间{size_t newcapacity = _capacity == 0 ? 6 : _capacity * 2;char* tmp = new char[newcapacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = newcapacity;}_str[_size] = ch;_size++;_str[_size] = '\0';    //_size的位置设置为\0}void append(char* str)     //追加字符串{size_t len = strlen(str);if (_size + len > _capacity)   //注意不能按2倍去增容{size_t newcapacity = _size + len;char* tmp = new char[newcapacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = newcapacity;}strcpy(_str + _size, str);_size += len;//_str[_size + len] = '\0'; strcpy已经把\0拷贝过去了}//s1+='ch' s1就是thisstring& operator+=(char ch){this->push_back(ch);return *this;}//s1+="ch" s1就是thisstring& operator+=(char* ch){this->append(ch);return *this;}string& insert(size_t pos, char ch)       //在pos位置插入字符{assert(pos <= _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;char* tmp = new char[newcapacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;//delete[] _str;  //注意这里不能写反了_capacity = newcapacity;}size_t end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;return *this;}string& insert(size_t pos, char* str)     //在pos位置插入字符串{assert(pos < _size);size_t len = strlen(str);if (_size + len > _capacity){size_t newcapacity = _size + len;char* tmp = new char[newcapacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = newcapacity;}size_t end = _size;while (end >= (int)pos){_str[end + len] = _str[end];   //这里是挪len个不是1个end--;}//strncpy也可以//strncpy(_str + pos, str, len);//strcpy会把\0拷贝过去,不可以//写个循环从pos依次往后放for (size_t i = 0; i < len; i++){_str[pos] = str[i];pos++;}_size += len;//返回自己return *this;}string& erase(size_t pos, size_t len = npos){assert(pos < _size);if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{size_t i = pos + len;while (i <= _size){_str[i - len] = _str[i];i++;}_size = _size - len;}return *this;}size_t find(char ch, size_t pos)     //在pos位置查找字符{for (size_t i = pos; i < _size; i++){if (_str[i] == ch){return i;}}return npos;}size_t find(char* str, size_t pos)   //在pos位置查找字符串{char* p = strstr(_str, str);if (p == NULL){return npos;}else{return (p - str);}}void resize(size_t newsize, char ch = '\0')  //填充字符ch{if (newsize < _size)   //第三种情况{_str[newsize] = '\0';_size = newsize;}else{if (newsize > _capacity)   //增加容量{size_t newcapacity = newsize;char* tmp = new char[newcapacity];strcpy(tmp, _str);delete[]_str;_str = tmp;_capacity = newcapacity;}for (size_t i = _size; i < newsize; i++)  //把字符ch往_size后面填{_str[i] = ch;}_size = newsize;_str[_size] = '\0';}}iterator begin()                //iterator迭代器的原理{return _str;}iterator end(){return (_str + _size);}const char* c_str(){return _str;}char& operator[](size_t i)   //重载[]可以遍历输出字符串,加&是既可以读,也可以写{assert(i < _size);return _str[i];}const char& operator[](size_t i) const{assert(i < _size);return _str[i];}//s1<s s1就是thisbool operator<(const string& s){int ret = strcmp(_str, s._str);return ret < 0;}bool operator<=(const string& s){return *this < s || *this == s;}bool operator>(const string& s){return !(*this <= s);}bool operator>=(const string& s){return !(*this < s);}bool operator==(const string& s){int ret = strcmp(_str, s._str);return ret == 0;}bool operator!=(const string& s){return !(*this == s);}bool empty(){return _size == 0;}size_t size()                   //求字符串的大小{return _size;}size_t capacity()              //求字符串的容量{return _capacity;}private:char* _str;size_t _size;              //已经有多少个有效字符个数size_t _capacity;          //能存多少个有效字符个数 \0不是有效字符,\0是标识结束的字符static size_t npos;       //insert用的位置};size_t string::npos = -1;std::ostream& operator<<(std::ostream& _out, string& s) 	//重载输出运算符<<{for (size_t i = 0; i < s.size(); i++){std::cout << s[i];}return _out;}std::istream& operator>>(std::istream& _in, string& s)     //重载输入运算符<<{//for (size_t i = 0; i < s.size(); i++)  错误写法//{//	std::cin >> s[i];//}while (1){char ch;ch = _in.get();if (ch == ' ' || ch == '\n'){break;}else{s += ch;}}return _in;}//std::istream& operator>>(std::istream& _in, string &s)     //重载输入运算符<<//{//	//for (size_t i = 0; i < s.size(); i++)  错误写法//	//{//	//	std::cin >> s[i];//	//}//	while (1)//	{//		char ch;//		ch = _in.get();//		if ( ch == '\n')//		{//			break;//		}//		else//		{//			s += ch;//		}//	}//	return _in;//}void TestString1(){string s1;string s2("bit");for (size_t i = 0; i < s1.size(); i++){std::cout << s1[i] << " ";}std::cout << std::endl;for (size_t i = 0; i < s2.size(); i++){std::cout << s2[i] << " ";}std::cout << std::endl;}void TestString2(){string s1;string s2("bit");std::cout << s1 << std::endl;std::cout << s2 << std::endl;s1.push_back('b');std::cout << s1 << std::endl;s2.push_back(' ');std::cout << s2 << std::endl;s1 += 'a';std::cout << s1 << std::endl;s2.insert(1, 'a');std::cout << s2 << std::endl;std::cout << s2.size() << std::endl;std::cout << s2.capacity() << std::endl;}void TestString3(){string s1;std::cin >> s1;std::cout << s1 << std::endl;}
}

测试代码:

#define _CRT_SECURE_NO_WARNINGS   1
#include"string.h"
int main()
{yyw::TestString1();yyw::string s3("hello");yyw::string::iterator it = s3.begin();while (it != s3.end()){std::cout << *it << " ";it++;}std::cout << std::endl;for (auto e : s3){std::cout << e << " ";}std::cout << std::endl;yyw::TestString2();yyw::TestString3();return 0;
}

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

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

相关文章

图论(蓝桥杯 C++ 题目 代码 注解)

目录 迪杰斯特拉模板&#xff08;用来求一个点出发到其它点的最短距离&#xff09;&#xff1a; 克鲁斯卡尔模板&#xff08;用来求最小生成树&#xff09;&#xff1a; 题目一&#xff08;蓝桥王国&#xff09;&#xff1a; 题目二&#xff08;随机数据下的最短路径&#…

爬虫练习:获取某网站高清壁纸

一、相关网站 二、查看robots.txt 三、相关代码 import requests from lxml import etree import osheaders {user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 } #发送请求 list_url https:/…

stm32使用时钟生成PWM时调用__HAL_TIM_SetAutoreload导致PWM消失处理

stm32使用时钟生成PWM时调用__HAL_TIM_SetAutoreload导致PWM消失处理 这一个是配置的时候没有使用影子寄存器导致的, 如果加载的Autoreload的值比原来的这一个值小, 这是会出现一个问题, 如果计数器里面的值记为Count, 如果改变的时候New_Autoreload < Count < Old_Auto…

CCCorelib 点云球形特征(CloudCompare内置算法库)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里基于每个点的邻域协方差来获取点云中具有的球形几何特征的点,计算方式如下图所示: 二、实现代码 // CloudCompare #include <CCCoreLib/PointCloudTpl.h> #include <CCCoreLib/

spring-boot操作elasticsearch

一、环境准备 springboot与elasticsearch的更新都非常快&#xff0c;为了避免兼容性问题&#xff0c;要注意下选择的版本问题。具体的可参考官网 --> springboot与elasticsearch版本兼容性 1.1导入依赖 <dependencies><dependency><groupId>org.spring…

k8s的pod和svc相互访问时网络链路解析

k8s的pod和svc相互访问时网络链路解析 1. k8s环境中pod相互访问1.1. k8s中pod相互访问的整体流程1.2. k8s的相同机器的不同pod相互访问1.3. k8s的不同机器的不同pod相互访问 3. k8s访问svc3.1 nat操作3.2 流量进入到后端pod 4. 疑问和思考4.1 访问pod相互访问为什么不用做nat?…

保研复习数据结构记(9)--基数排序

基数排序的过程&#xff1f;首先设置r个&#xff08;r&#xff1a;每个关键字位可以对应多少取值&#xff09;空队列&#xff0c;&#xff0c;按照各个关键字位权重递增的次序&#xff08;个、十、百&#xff09;&#xff0c;将d个元素&#xff08;关键字可以被拆分成d个部分&a…

金枪鱼群优化算法TSO优化BiLSTM-ATTENTION实现风力发电功率预测(matlab)

金枪鱼群优化算法TSO优化BiLSTM-ATTENTION实现风力发电功率预测&#xff08;matlab&#xff09; TSO-BiLSTM-Attention金枪鱼群算法优化长短期记忆神经网络结合注意力机制的数据回归预测 Matlab语言。 金枪鱼群优化算法&#xff08;Tuna Swarm Optimization&#xff0c;TSO)是一…

生成式人工智能服务安全基本要求实务解析

本文尝试明晰《基本要求》的出台背景与实践定位&#xff0c;梳理《基本要求》所涉的各类安全要求&#xff0c;以便为相关企业遵循执行《基本要求》提供抓手。 引言 自2022年初以来&#xff0c;我国陆续发布算法推荐、深度合成与生成式人工智能服务相关的规范文件&#xff0c;…

丘一丘正则表达式

正则表达式(regular expression,regex,RE) 正则表达式是一种用来简洁表达一组字符串的表达式正则表达式是一种通用的字符串表达框架正则表达式是一种针对字符串表达“简洁”和“特征”思想的工具正则表达式可以用来判断某字符串的特征归属 正则表达式常用操作符 操作符说明实…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Search)

搜索框组件&#xff0c;适用于浏览器的搜索内容输入框等应用场景。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 Search(options?: { value?: string, placeholder?: Reso…

混合云构建-VPN打通阿里云和Azure云

要在阿里云和Azure云之间通过VPN打通网络,您需要在两边分别设置VPN网关,并配置相应的连接和路由规则以确保两个云环境之间的网络流量可以互通。以下是一个基本的步骤指南: 为了更具体地说明如何在阿里云和Azure之间通过VPN打通网络,我们将通过一个简化的示例来演示整个过程…

ArcGIS JSAPI 学习教程 - ArcGIS Maps SDK for JavaScript 不同版本4.8-4.28(最新版)离线部署

ArcGIS JSAPI 学习教程 - ArcGIS Maps SDK for JavaScript 不同版本4.8-4.28&#xff08;最新版&#xff09;SDK离线部署 测试资源4.18 以及之前版本4.19 以及之后版本 接触一段时间 ArcGIS JSAPI 之后&#xff0c;整体感觉还好&#xff0c;后来需要解决不同版本问题&#xff0…

redis中通用命令以及key过期策略

通用命令 exists 判断某个key是否存在。 exists key时间复杂度&#xff1a;O(1) 返回值&#xff1a;key 存在的个数。 del 删除指定的 key&#xff0c;可以一次删除一个或者多个。 del key时间复杂度&#xff1a;O(1) 返回值&#xff1a;删除掉的 key 的个数。 expire…

数据结构·复杂度

目录 1 时间复杂度 2 大O渐进表示法 举例子&#xff08;计算时间复杂度为多少&#xff09; 3 空间复杂度 前言&#xff1a;复杂度分为时间复杂度和空间复杂度&#xff0c;两者是不同维度的&#xff0c;所以比较不会放在一起比较&#xff0c;但是时间复杂度和空间复杂度是用…

汉服|高校汉服租赁网站|基于Springboot的高校汉服租赁网站设计与实现(源码+数据库+文档)

高校汉服租赁网站目录 目录 基于Springboot的高校汉服租赁网站设计与实现 一、前言 二、系统设计 三、系统功能设计 1、汉服信息管理 2、汉服租赁管理 3、公告管理 4、公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选…

SQL Server错误:15404

执行维护计划失败&#xff0c;提示SQL Server Error 15404 无法获取有关... 异常如下图&#xff1a; 原因&#xff1a;数据库用户名与计算机名称不一致 解决办法&#xff1a;1.重名称数据库用户名 将前缀改成计算机名 2.重启SQL Server代理

【数据挖掘】实验1:R入门(内含详细R和RStudio安装教程)

实验1&#xff1a;R入门 一&#xff1a;实验目的与要求 1&#xff1a;根据上课PPT内容&#xff0c;掌握课堂知识并进行代码练习操作&#xff0c;提供练习过程和结果。 2&#xff1a;可COPY代码运行结果直接提交&#xff0c;如涉及到输出图等可截图。 二&#xff1a;实验内容 …

免费搭建导航网站教程带免费空间域名源码

使用免费空间和免费域名免费搭建一个导航网站 手把手视频教程 https://pan.xunlei.com/s/VNsoMehs7RCjz3IClV6h2vNMA1?pwdq596#

中国首个基于区块链的分布式算力网络上线

随着美国人工智能公司OpenAI近期发布的Sora视频模型&#xff0c;全球对高性能算力的需求突破了历史新高。Sora的创新在于它能够以超长生成时间、多角度镜头捕捉&#xff0c;理解物理世界的能力&#xff0c;这不仅是技术的一大突破&#xff0c;更是对算力需求的一大挑战。在这样…