C++ string类(二)及深浅拷贝
一、string类方法使用举例
1.迭代器
迭代器本质:指针(理解)
迭代器:正向迭代器: begin() | end() 反向迭代器: rbegin() | rend()
2.find使用
//找到s中某个字符
void TestString3()
{string s("AAADEFNUIENFUIAAA");//找到AAA位置size_t pos = s.find("AAA");cout << pos << endl;
}
输出0,表示0位置处为AAA
3.获取文件后缀/substr
substr(pos = 0, n = npos);
从Pos位置开始,截取n个字符,如果n没有传递,表示从pos一直截取到末尾
如果都没有传递,截取整个字符
void TestString3()
{string s("124.text.cpp");//rfind从后面往前找 ’.’,+1找到后缀位置size_t pos =s.rfind('.') + 1;//从pos处截到末尾string postfix = s.substr(pos);cout << postfix << endl;
}

4.给多行单词,获取每行单词中最后一个单词的长度/getline
int main()
{string line;// 不要使用cin>>line,因为会它遇到空格就结束了// while(cin>>line)while (getline(cin, line)){size_t pos = line.rfind(' ');cout << line.size() - pos - 1 << endl;}return 0;
}
getline(cin,s): 获取一整行字符串,字符串中如果包含空格等空白字符也可以接收
oj练习
5.比大小
void Test()
{string s1("abc");string s2("afwef");if (s1 < s2){cout << "s1<s2" << endl;}else if (s1>s2){cout << "s1>s2" << endl;}else{cout << "s1=s2" << endl;}
}
6.其他一些练习OJ
反转字母OJ
找第一个出现的相同的字符
验证回文串
二. string类的模拟实现
1. 浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规

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

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供

3.String类的模拟实现
正确实现String
深拷贝,传统版本
class String
{
public:String(const char* str = ""){if (nullptr == str)str == "";_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s):_str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);}String& operator=(const String& s){if (this != &s){char* pStr = new char[strlen(s._str) + 1];strcpy(pStr, s._str);delete[] _str;_str = pStr;}return *this;}~String(){if (_str){delete[]_str;_str = nullptr;}}
private:char* _str;
};void TestString()
{String s1("hello");String s2(s1);String s3(s2);
}
int main()
{TestString();return 0;
}
如下,每个对象都有自己独立的空间,释放时也是,只释放自己的互不影响

深拷贝(现代版写法)
减少传统代码重复,相似性代码进行优化
class String
{
public:String(const char* str = ""){if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s): _str(nullptr)//_Str可能为随机指针,要先置为空{String strTmp(s._str);swap(_str, strTmp._str);//交换地址}String& operator=(String s)//赋值运算符重载,先传入参数{swap(_str, s._str);//return *this;}
4.写时拷贝
写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源
三、string模拟实现代码(全部)
#include <assert.h>
#include<iostream>
#include<string>
using namespace std;
namespace zx
{class string{public:typedef char* iterator;///// 构造string(const char* str = ""){if (nullptr == str)str = "";_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& s){string temp(s._str);this->swap(temp);}string(size_t n, char val){_str = new char[n + 1];memset(_str, val, n);_str[n] = '\0';_size = n;_capacity = n;}string& operator=(string s){this->swap(s);return *this;}~string(){if (_str){delete[] _str;_str = nullptr;_capacity = 0;_size = 0;}}/// 迭代器iterator begin(){return _str;}iterator end(){return _str + _size;}/// 容量size_t size()const{return _size;}size_t length()const{return _size;}size_t capacity()const{return _capacity;}bool empty()const{return 0 == _size;}void clear(){_size = 0;}void resize(size_t newsize, char val){size_t oldsize = size();if (newsize > oldsize){// 有效元素个数增多if (newsize > capacity())reserve(newsize);// 多出的元素使用val填充memset(_str + _size, val, newsize - _size);}_size = newsize;_str[_size] = '\0';}void resize(size_t newsize){resize(newsize, '\0');}void reserve(size_t newcapacity){size_t oldcapacity = capacity();if (newcapacity > oldcapacity){// 1. 申请新空间char* temp = new char[newcapacity + 1];// 2. 拷贝元素strncpy(temp, _str, _size);// 3. 释放旧空间delete[] _str;// 4. 使用新空间_str = temp;_capacity = newcapacity;_str[_size] = '\0';}}// 元素访问char& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}char& at(size_t index){// 如果越界,抛出out_of_range的异常return _str[index];}const char& at(size_t index)const{// 如果越界,抛出out_of_range的异常return _str[index];}//// modifyvoid push_back(char ch){*this += ch;}string& operator+=(char ch){if (_size == _capacity)reserve((size_t)_capacity*1.5 + 3);_str[_size] = ch;++_size;_str[_size] = '\0';return *this;}string& operator+=(const char* str){size_t needSpace = strlen(str);size_t leftSpace = capacity() - size();if (needSpace > leftSpace){reserve(capacity()+ needSpace);}strcat(_str, str);_size += needSpace;_str[_size] = '\0';return *this;}string& operator+=(const string& s){*this += s.c_str();return *this;}string& append(const char* str){*this += str;return *this;}string& appent(const string& s){*this += s;return *this;}string& insert(size_t pos, const string& s);string& erase(size_t pos = 0, size_t n = npos);void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}const char* c_str()const{return _str;}size_t find(char ch, size_t pos = 0)const{if (pos >= _size){return npos;}for (size_t i = pos; i < _size; ++i){if (_str[i] == ch)return i;}return npos;}size_t rfind(char c, size_t pos = npos){if (pos >= _size){pos = _size-1;}for (int i = pos; i >= 0; --i){if (_str[i] == c)return i;}return npos;}string substr(size_t pos = 0, size_t n = npos) const{// 从pos位置开始,往后借助n个字符长度if (pos >= _size){return string();}// 从pos到字符串的末尾剩余字符个数n = min(n, _size - pos);string temp(n, '\0');size_t index = 0;for (size_t i = pos; i < pos+n; ++i){temp[index++] = _str[i];}return temp;}private:char* _str;size_t _size;size_t _capacity;const static size_t npos = -1;friend ostream& operator<<(ostream& out, const string& s);};ostream& operator<<(ostream& out, const string& s){for (size_t i = 0; i < s.size(); ++i){cout << s[i];}return out;}
}int main()
{// TestMyString01();// TestMyString02();// TestMyString03();TestMyString04();_CrtDumpMemoryLeaks();return 0;
}
相关文章:

C++ string类(二)及深浅拷贝
一、string类方法使用举例1.迭代器迭代器本质:指针(理解)迭代器:正向迭代器: begin() | end() 反向迭代器: rbegin() | rend()2.find使用//找到s中某个字符 void TestString3() {string s("AAADEFNUIE…...

「TCG 规范解读」TCG 软件栈 TSS (上)
可信计算组织(Ttrusted Computing Group,TCG)是一个非盈利的工业标准组织,它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立,并采纳了由可信计算平台联盟(the Trusted Computing Platform Alli…...
(二)Markdown编辑器的使用效果 | 以CSDN自带MD编辑器为例
Markdown编辑器使用指南 (一)Markdown编辑器的使用示例 | 以CSDN自带MD编辑器为例(二)Markdown编辑器的使用效果 | 以CSDN自带MD编辑器为例 这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题…...
WebSocket网络通信执行流程
目录WebSocket网络通信执行流程相关概念执行流程WebSocket网络通信执行流程 WebSocket协议:通过单个TCP连接在客户端和服务器之间建立全双工双向通信通道。 WebSocket 对象:提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接…...
【Shell学习笔记】4.Shell 基本运算符
前言 本章介绍Shell的基本运算符。 Shell 基本运算符 Shell 和其他编程语言一样,支持多种运算符,包括: 算数运算符关系运算符布尔运算符字符串运算符文件测试运算符 原生bash不支持简单的数学运算,但是可以通过其他命令来实现…...

无代码资讯 | 《低代码开发平台能力要求》发布;CADP列入Gartner《2022-2024 中型企业技术采用路线图》
栏目导读:无代码资讯栏目从全球视角出发,带您了解无代码相关最新资讯。TOP3 大事件1、《低代码开发平台能力要求》团体标准正式发布近日,中国电子工业标准化协会发布公告(中电标【2022】037 号),由中国电…...

智能家居Homekit系列一智能插座
WiFi智能插座对于新手接触智能家居产品更加友好,不需要额外购买网关设备 很多智能小配件也给我们得生活带来极大的便捷,智能插座就是其中之一,比如外出忘记关空调,可以拿起手机远程关闭。 简单说就是:插座可以连接wi…...

React(三):脚手架、组件化、生命周期、父子组件通信、插槽
React(三)一、脚手架安装和创建1.安装脚手架2.创建脚手架3.看看脚手架目录4.运行脚手架二、脚手架下从0开始写代码三、组件化1.类组件2.函数组件四、React的生命周期1.认识生命周期2.图解生命周期(1)Constructor(2&…...

2023年电子竞技行业报告
第一章 行业概况 电子竞技也被称为电竞或eSports,是一种电子游戏的竞技活动,玩家在这里与其他人或团队对战,通常是在网络上或特定场地上进行。 电子竞技行业的发展与互联网和计算机技术的进步密不可分,同时还受到游戏开发商、赞…...

小朋友就餐-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)
【案例8-5】 小朋友就餐问题 【案例介绍】 1.任务描述 一圆桌前坐着5位小朋友,两个人中间有一只筷子,桌子中央有面条。小朋友边吃边玩,当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭。但是,小朋友在吃…...

大数据|Hadoop系统
目录 📚Hadoop介绍 📚Hadoop优点 📚Hadoop的体系结构 🐰HDFS的体系结构 🐰MapReduce的体系结构 🐰HDFS和MapReduce的协同作用 📚Hadoop与分布式开发 🐰MapReduce计算模型 &a…...

2.递归算法
递归算法的两个特点(很重要)调用自身要有结束条件void func1(int x) {printf("%d\n", x);func1(x - 1); }func1会一直死循环,没有使其结束的条件,所以不是递归void func2(int x) {if (x > 0){printf("%d\n"…...
MySQL---触发器
MySQL—触发器 将两个关联的操作步骤写到程序里面,并且要用事务包裹起来,确保两个操作称为一个原子操作,要么全部执行,要么全部不执行 创建一个触发器,让商品信息数据的插入操作自动触发库存数据的插入操作 …...

PXC高可用集群(MySQL)
1. PXC集群概述 1.1. PXC介绍 Percona XtraDB Cluster(简称PXC) 是基于Galera的MySQL高可用集群解决方案Galera Cluster是Codership公司开发的一套免费开源的高可用方案PXC集群主要由两部分组成:Percona Server with XtraDB(数据…...

pytorch-把线性回归实现一下。原理到实现,python到pytorch
线性回归 线性回归输出是一个连续值,因此适用于回归问题。回归问题在实际中很常见,如预测房屋价格、气温、销售额等连续值的问题。 与回归问题不同,分类问题中模型的最终输出是一个离散值。所说的图像分类、垃圾邮件识别、疾病检测等输出为离…...
js中判断数组的方式有哪些?
js中判断数组的方式有哪些?1.通过Object.prototype.toString.call来判断2.通过instanceof来判断3.通过constructor来判断4.通过原型链来判断5.通过ES6.Array.isAaary()来判断6.通过Array.prototype.isPrototypeOf来判断1.通过Object.prototype.toString.call来判断 …...

【2023unity游戏制作-mango的冒险】-5.攻击系统的简单实现
👨💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 收录于专栏:unity游戏制作 ⭐攻击系统的简单实现⭐ 文章目录⭐攻击系统的简单实现⭐👨…...

SpringMVC 面试题
1、什么是SpringMVC? SpringMVC是一个基于Java的实现了MVC设计模式的“请求驱动型”的轻量级WEB框架,通过把model,view,controller 分离,将web层进行职责的解耦,把复杂的web应用分成逻辑清晰的几个部分&am…...

布局三八女王节,巧借小红书数据分析工具成功引爆618
对于小红书“她”经济来说,没有比三八节更好的阵地了。伴随三八女王节逐渐临近,各大品牌蓄势待发,这场开春后第一个S级大促活动,看看品牌方们可以做什么? 洞察流量,把握节点营销时机 搜索小红书2023年的三…...

RISCV学习(1)基本模型认识
笔者来聊聊ARM的函数的调用规则 1、ARM函数调用规则介绍 首先介绍几个术语, AAPCS:Procedure Call Standard for the ARM ArchitectureAPCS:ARM Procedure Call StandardTPCS:Thumb Procedure Call StandardATPCS:AR…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...