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…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...