16.C++STL 3(string类的模拟,深浅拷贝问题)
⭐本篇重点:string类的模拟,自己实现一个简单的string类
⭐本篇代码:c++学习/05.string类的学习 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)
目录
一. 经典string类的模拟
1.1 深浅拷贝问题
1.2 使用深拷贝完成经典string类的模拟
a size函数
b 拷贝构造函数
c 赋值运算符重载
d operator[]重载
二. 现代写法的string类模拟
2.1 拷贝构造函数
2.2 赋值运算符重载
三. 下篇文章:STL中vector的使用
一. 经典string类的模拟
实现一个简单的string类,主要是实现string类的构造函数,析构函数,拷贝构造函数,赋值运算符重载。这个过程需要我们首先理解深浅拷贝的问题。
1.1 深浅拷贝问题
浅拷贝问题:如果我们初始化一个对象的时候,只是简单的将另一个对象的值赋值给这个对象。比如我们在堆上申请的空间。当我们销毁这两个对象的时候,由于它们指向同一个空间,这个空间就会被销毁两次。程序就会崩溃。
测试代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
using namespace std;namespace yzc
{class string{public:string(const char* str = ""):_str(new char[strlen(str) + 1]){cout << "调用构造函数" << endl;strcpy(_str, str);}//拷贝构造string(const string& str){*this = str;}~string(){cout << "调用析构函数" << endl;delete[] _str;}void print(){cout << _str << endl;}private:char* _str;};
}int main()
{yzc::string s1 = "123456";yzc::string s2 = "abcdef";s1.print();s2.print();return 0;
}
没有调用拷贝构造函数,可以正常输出。
运行结果如下:

如果我们使用拷贝构造函数
int main()
{yzc::string s1 = "123456";yzc::string s2(s1);return 0;
}
分析代码可知,由于浅拷贝问题。输出一次调用构造函数和两次析构函数后程序崩溃
只有使用深拷贝,我们在拷贝构造函数里面重新申请一份空间,然后重新全部复制才行。

1.2 使用深拷贝完成经典string类的模拟
a size函数
为了完成深拷贝,我们需要定义一个size函数用于求_str的长度。加上const,因为函数内部并不会更改任何值
int size()const{return strlen(_str);}
b 拷贝构造函数
与构造函数类似,我们重新开辟一份空间,然后使用strcpy进行拷贝
//拷贝构造,使用深拷贝完成拷贝string(const string& s):_str(new char[s.size()]){strcpy(_str, s._str);}
测试代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
using namespace std;namespace yzc
{class string{public:string(const char* str = ""):_str(new char[strlen(str) + 1]) //由于C语言字符串后面都带'\0',需要加上1{strcpy(_str, str);}拷贝构造//string(const string& str)//{// *this = str;//}//拷贝构造,使用深拷贝完成拷贝string(const string& s):_str(new char[s.size() + 1]) //一定要注意要加1,否则会越界访问{strcpy(_str, s._str);}~string(){delete[] _str;_str = nullptr;}int size()const{return strlen(_str);}void print(){cout << _str << endl;}private:char* _str;};
}int main()
{yzc::string s1 = "123456";yzc::string s2(s1);s1.print();s2.print();return 0;
}
测试结果

c 赋值运算符重载
与拷贝构造函数一样,要注意深浅拷贝的问题
//赋值运算符重载string& operator=(const string& s){if (this != &s)//地址不同才进行赋值{delete[] _str; //释放原地址空间,防止内存泄漏//定义中间变量tmp用于拷贝char* tmp = new char[s.size() + 1]; //注意要 + 1strcpy(tmp, s._str);_str = tmp;}return *this; //返回当前对象,为了支持 a = b = c}
测试:主函数代码如下
int main()
{yzc::string s1 = "123456";yzc::string s2 = "abcdef";yzc::string s3 = s1;yzc::string s4;s4 = s2;s3.print();s4.print();return 0;
}
测试结果:

d operator[]重载
我们还能重载[]这个操作符,方便我们遍历整个字符串
直接输入i,返回_str[i]即可(注意const)
char& operator[](size_t i){assert(i < size());return _str[i];}const char& operator[](size_t i)const{assert(i < size());return _str[i];}
测试代码:
int main()
{yzc::string s1 = "159753468244";for (int i = 0; i < s1.size(); i++){cout << s1[i] << " ";}cout << endl;return 0;
}
运行结果:

二. 现代写法的string类模拟
2.1 拷贝构造函数
为了提高代码的复用,我们在拷贝构造函数中使用构造函数去构造一个对象,然后交换当前对象和这个对象。
代码如下:
//现代版写法string(const string& s):_str(nullptr){string strTmp(s._str); //使用构造函数将s._str构造一个tmpswap(_str, strTmp._str);//交换_str和tmp}
交换后,strTmp由于是局部变量就直接被销毁了! 而我们创建的对象被保留
2.2 赋值运算符重载
我们使用传值方法传参,交换_str后我们成功创建的对象。且不会影响传入的对象
//现代版写法string& operator=(string s) //不使用引用传参,而是传值{swap(_str, s._str);return *this;}
测试代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
using namespace std;namespace yzc
{class string{public:string(const char* str = ""):_str(new char[strlen(str) + 1]) //由于C语言字符串后面都带'\0',需要加上1{strcpy(_str, str);}拷贝构造,使用深拷贝完成拷贝//string(const string& s)// :_str(new char[s.size() + 1]) //注意要加1//{// strcpy(_str, s._str);//}//现代版写法string(const string& s):_str(nullptr){string strTmp(s._str); //使用构造函数将s._str构造一个tmpswap(_str, strTmp._str);//交换_str和tmp}赋值运算符重载//string& operator=(const string& s)//{// if (this != &s)//地址不同才进行赋值// {// delete[] _str; //释放原地址空间,防止内存泄漏// //定义中间变量tmp用于拷贝// char* tmp = new char[s.size() + 1];// strcpy(tmp, s._str);// _str = tmp;// // }// return *this; //返回当前对象,为了支持 a = b = c//}//现代版写法string& operator=(string s) //不使用引用传参,而是传值{swap(_str, s._str);return *this;}~string(){delete[] _str;_str = nullptr;}size_t size()const{return strlen(_str);}void print(){cout << _str << endl;}private:char* _str;};
}int main()
{yzc::string s1 = "123456";yzc::string s2(s1);yzc::string s3 = s1;s1.print();s2.print();s3.print();return 0;
}
运行结果:

三. 下篇文章:STL中vector的使用
相关文章:
16.C++STL 3(string类的模拟,深浅拷贝问题)
⭐本篇重点:string类的模拟,自己实现一个简单的string类 ⭐本篇代码:c学习/05.string类的学习 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) 目录 一. 经典string类的模拟 1.1 深浅拷贝问题 1.2 使用深拷贝完成经典string类的…...
神经网络10-Temporal Fusion Transformer (TFT)
Temporal Fusion Transformer (TFT) 是一种专为时序数据建模而设计的深度学习模型,它结合了Transformer架构和其他技术,旨在有效地处理和预测时序数据中的复杂模式。TFT 于 2020 年由 Google Research 提出,旨在解决传统模型在时序预测中的一…...
“iOS profile文件与私钥证书文件不匹配”总结打ipa包出现的问题
目录 文件和证书未加载或特殊字符问题 证书过期或Profile文件错误 确认开发者证书和私钥是否匹配 创建证书选择错误问题 申请苹果 AppId时勾选服务不全问题 总结 在上线ios平台的时候,在Hbuilder中打包遇见了问题,生成ipa文件时候,一…...
《图像梯度与常见算子全解析:原理、用法及效果展示》
简介:本文深入探讨图像梯度相关知识,详细介绍图像梯度是像素灰度值在不同方向的变化速度,并以 “pig.JPG” 图像为例,通过代码展示如何选取图像部分区域并分析其像素值以论证图像梯度与边缘信息的关联。接着全面阐述了 Sobel 算子,…...
【c++篇】:探索c++中的std::string类--掌握字符串处理的精髓
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨文章所属专栏:c篇–CSDN博客 文章目录 前言一.std::string对象的创建二.std::string对象的访问三.std::str…...
LlamaIndex ollama 搭建本地RAG应用,建立本地知识库
目录 简介安装前的准备下载ollama创建llamaindex conda环境,为后面编码作准备 环境变量迁移ollama到其他盘运行ollama方式一方式二禁止ollama开机自启动运行第一个模型 Chatbox聊天下载Chatbox配置ollama地址和模型验证 建立自身特定知识数据搭配大语言模型创建项目…...
draggable的el-dialog实现对话框标题可以选择
请看图 这个对话框使用了el-dialog并且draggable属性设置成了true,所以标题栏这里就可以拖动,现在用户想选中标题栏的文本进而复制。我看到这个需求头都大了。 我能想到的方案有三个:1. 取消draggable为true 2. 标题文案后面加一个复制按钮 …...
2024年Android面试总结
2024年Android面试总结 1.动画类型有哪些?插值器原理? 2.StringBuffer和StringBuilder区别? 3.jvm内存模型? 4.线程池7大核心参数及原理? 5.Android多进程通信方式有哪些?各自的优缺点? 6…...
树莓派3:64位系统串口(UART)使用问题的解决方法
前言 当我们要使用串口进行zigbee的短距离通信时,发现无法使用串口. 原因 树莓派3bCPU内部有两个串口,一个硬件串口(就是我们平时使用的UART),还有一个迷你串口(mini-uart),在老版本的树莓派中把硬件串口分配在GPIO上,可以单独使用.但是在新的树莓派中官方把硬件串口给了蓝牙…...
SemiDrive E3 硬件设计系列---唤醒电路设计
一、前言 E3 系列芯片是芯驰半导体高功能安全的车规级 MCU,对于 MCU 的硬件设计部分,本系列将会分模块进行讲解,旨在介绍 E3 系列芯片在硬件设计方面的注意事项与经验,本文主要讲解 E3 硬件设计中唤醒电路部分的设计。 二、RTC 模…...
淘宝接口高并发采集核心要点解读,开启电商数据智能应用新纪元
一、引言 在电商蓬勃发展的今天,淘宝作为全球知名的电商巨头,其平台上的数据犹如一座蕴藏无限价值的宝藏。准确且高效地采集淘宝接口数据,并通过高并发技术实现大规模数据获取,对于电商企业的精准营销、市场趋势分析、竞品监测以及…...
C#里怎么样快速使用LINQ实现查询?
C#里怎么样快速使用LINQ实现查询? 在C#里使用LINQ,是一个方便的功能, 不过,要学会使用这部分的功能,需要比较多的学习时间,否则,使用起就比较难。 因为它的表现方式,与编程语言通用的功能,还是差别比较大。 当数据量比较小,没有特定的顺序时,使用LINQ访问会比较好…...
2024新版微软edge浏览器输入百度网址时自动补全tn=68018901……小尾巴的解决
以前一直是Windows11 21h2版本,浏览器内输入baidu不会自动补全tnxx的百度推广小尾巴。然后前几天在BIOS内开启了tpm2.0,升级Windows11到了24h2版本。 发现在edge浏览器内只要输入b,就会自动补全为baidu.com?tnXXX的这么一个百度推广形式。开…...
uni-app打包H5自定义微信分享
1、配置分享信息 修改uni-app的index.html,添加Open Graph(OG)标签来配置分享信息。 <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="description" content="标题"/>…...
大模型专栏--大模型应用场景
紧接着第一篇,什么是大模型,这篇文章讨论一下大模型的应用场景和应用方式有哪些? 基础使用 随着 GPT 的出现,AI 大模型已经越来越多得出现在日常生活和学术研究,工作中。 按照使用方向有以下几种: 自然语…...
骑砍2霸主MOD开发(29)-顶点动画
一.定制化顶点动画(MorphAnimation) 定制化顶点动画用于人物Agent的面部表情. 1.创建MorphAnimation对应静态资源morph_animation.tpac 2.Agent设置对应MorphAnimation [EngineMethod("set_agent_facial_animation", false)] void SetAgentFacialAnimation(UIntPtr …...
-Dspring.profiles.active=dev与--spring.profiles.active=dev的区别
在Spring Boot应用程序中,-Dspring.profiles.activedev和--spring.profiles.activedev都用于指定要激活的Spring配置文件(profile),但它们在不同的环境中使用,并且有不同的作用域。 -Dspring.profiles.activedev&#…...
面向对象高级(2)单例设计对象与代码块
面向对象高级(2) 单例设计模式、main方法与代码块 引言; 设计模式:特定环境下特定问题的处理方法。可理解为一种经典的可以参照的模板。单例设计模式则是只存在单个对象实例、且只有一种方法获取对象实例的一种设计模式。 单例设…...
47小型项目的规划与实施
每天五分钟学Linux | 第四十七课:小型项目的规划与实施 大家好!欢迎再次来到我们的“每天五分钟学Linux”系列教程。在前面的课程中,我们学习了并发编程的知识,包括如何管理和使用进程与线程。今天,我们将探讨如何规划…...
堤防安全监测系统方案
一、背景情况 堤防是开发利用水资源和防治水灾害的重要工程措施之一,对防洪、供水、生态、发电、航运等至关重要。我国现有堤防9.8万多座,其中大中型堤防4700多座、小型堤防9.4万座,80%以上修建于上世纪50至70年代。由于堤防管护力量薄弱&am…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
02-性能方案设计
需求分析与测试设计 根据具体的性能测试需求,确定测试类型,以及压测的模块(web/mysql/redis/系统整体)前期要与相关人员充分沟通,初步确定压测方案及具体的性能指标QA完成性能测试设计后,需产出测试方案文档发送邮件到项目组&…...
Python网页自动化测试,DrissonPage库入门说明文档
🛰️ 基本逻辑 操作浏览器的基本逻辑如下: 创建浏览器对象,用于启动或接管浏览器获取一个 Tab 对象使用 Tab 对象访问网址使用 Tab 对象获取标签页内需要的元素对象使用元素对象进行交互 除此以外,还能执行更为复杂的操作&am…...
