手撕一个String类

news2024/10/12 3:23:16

习惯写Leetcode而不习惯写工程的在校同学,很大概率在处理细节时会感到陌生

类定义如下:

class String
{
public:
	String();//默认构造函数
	String(const char* str);//构造函数
	String(const String& other);//拷贝构造函数
	String(String&& other);//移动构造函数
	~String();//析构函数
	String& operator= (const String& other);//拷贝赋值函数
	String& operator= (String&& other);//移动赋值函数
private:
	char* m_data;
	int size;
};

主要是对c风格字符串的处理。

具体函数实现如下:

String::String() : m_data(new char[1]), size(0) {
	m_data[0] = '\0';
}

String::String(const char* str)//传递const char*字符串
{
	if (str == nullptr)
	{
		m_data = new char[1];
		*m_data = '\0';
		size = 0;
	}
	else
	{
		size = strlen(str);//strlen不包括标志符号
		m_data = new char[size+1];
		strcpy(m_data, str);
	}
}

String::~String()
{
	delete[] m_data;
}

String::String(const String& other)
{

	size = other.size;
	m_data = new char[size+1];
	strcpy(m_data, other.m_data);
}
//移动构造
String::String( String&& other) noexcept{
//在移动构造和移动复制中明确告诉编译器,不会抛出异常
	m_data = other.m_data;
	size = other.size;
	other.m_data = nullptr;
	other.size = 0;
}
//拷贝赋值
String& String::operator=(const String& other)
{
	if (this == &other)return *this;

	delete[] m_data;

	size = other.size;
	m_data = new char[size + 1];
	strcpy(m_data, other.m_data);
	return *this;
}

String& String::operator=(String && other) noexcept
{
	if (this != &other) {
		delete[] m_data;
		m_data = other.m_data;
		size = other.size;

		other.m_data = nullptr;
		other.size = 0;
	}
	return *this;
}

需要注意的点

1.成员初始化列表:

String::String() : m_data(new char[1]), size(0) {
	m_data[0] = '\0';
}

成员初始化列表的使用允许直接初始化类的成员变量。在默认构造函数中,m_datasize 在构造函数体执行之前已经被初始化。这种方式不仅简洁,还可以提高性能,避免不必要的赋值操作。

a.对于成员对象(类的成员变量是其他对象),在构造函数体中赋值会涉及:

  • 先调用成员对象的默认构造函数
  • 再在构造函数体中对其赋值,这样会引发不必要的对象构造与析构操作。

使用成员初始化列表可以直接构造成员对象,避免多余的对象操作,从而提高性能。

b.有些类型不能在构造函数体中使用赋值进行初始化,比如 const 成员变量和引用(&)。它们必须通过初始化列表进行初始化,因为它们的值一旦初始化就不能再改变。

在本例中,m_data 是一个指针,而 new char[1] 会动态分配一块内存。这种初始化可以直接在初始化列表中完成,保证在构造函数体执行之前,指针已经指向一块有效的内存区域。

2.使用动态内存分配:

这里使用new分配内存,而且分配的是字符数组,所以要使用delete[];

3.深拷贝:

拷贝构造函数执行深拷贝,即为新对象分配自己的内存空间,而不是简单地复制指针。这避免了多个对象共享同一块内存的风险,保证了每个对象独立管理自己的内存。

4.移动构造函数:

  • 右值引用String&& other 表示移动语义中接收的右值引用,可以直接“偷取”资源(指针和大小)而不是进行拷贝。
  • noexcept 关键字:使用 noexcept 明确表示该函数不会抛出异常,这对性能优化有帮助(特别是在某些容器的优化操作中,如 std::vector 会利用 noexcept 移动构造函数提高效率)。
  • 资源转移:将 other.m_data 的指针转移到当前对象,并将 other.m_data 置为 nullptr,确保其他对象不再拥有这块内存的控制权,避免重复释放。

5.拷贝赋值运算符:

  • 自赋值检测if (this == &other) 检测自赋值的情况,避免自赋值导致内存出错。
  • 删除旧数据:在进行新的拷贝之前,必须先释放当前对象所管理的内存,避免内存泄漏。
  • 深拷贝:重新分配内存并拷贝数据,确保赋值后的对象有自己独立的内存。

6.*this:

this 是一个指向当前对象的指针,而 *this 表示解引用该指针,即得到当前对象本身的引用。返回 *this 是为了实现链式调用和返回当前对象本身。

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

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

相关文章

2023年4月自考《数据库系统原理》04735试题

目录 一:选择题 二:填空题 三:设计题 四:简答题 五:综合题 一:选择题 1.在数据库系统中,专门用户建立和管理数据的软件是 (书中)P28页 A.DBS B.DB C.DBA D.DBMS 2.通常所说的数据库系统容不包括 (书中)P29页 A.应用程序 B.数据库管理员 C.用户 D.网络环境 …

Datawhale 组队学习 文生图 Prompt攻防 task01

文生图大模型面临着巨大的滥用风险,如生成虚假、违法违规、血腥恐怖或歧视仇恨的图片,评估此类模型和系统的安全防范能力至关重要。 赛题背景:从产业应用需求出发,体验为大模型注入生成式“风险疫苗”,透视大模型生图潜…

Java SE vs Java EE 与 JVM vs JDK vs JRE

Java SE(Java Platform,Standard Edition): Java 平台标准版,Java 编程语言的基础,它包含了支持 Java 应用程序开发和运行的核心类库以及虚拟机等核心组件。Java SE 可以用于构建桌面应用程序或简单的服务器应用程序。…

聚类分析 | IPOA优化FCM模糊C均值聚类优化算法

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 (多图聚类)IPOA优化FCM模糊C均值聚类优化算法,matlab代码,超多图 基于改进的鹈鹕优化算法(IPOA)优化FCM模糊C均值聚类优化,matlab代码,直接运行…

万字长文解读预测市场的历史发展与未来前景

撰文:Alex Nardi,Shoal Research 编译:Yangz,Techub News 文章要点: 预测市场的发展和影响:预测市场利用集体智慧预测未来事件的能力日益得到认可,对政治、金融、娱乐和流行文化等领域产生了重…

HiRT | 异步控制策略,告别VLA时延问题

论文:HiRT: Enhancing Robotic Control with Hierarchical Robot Transformers 前言:HiRT 通过异步处理的策略,将 VLM 作为低频慢思考过程,将轻量的动作策略模型作为高频快响应过程 ,以此解决 VLA 驱动带来的控制时延问…

Ubuntu22.04环境下源码安装OpenCV 4.8.1

因为项目需要用OpenCV对yolov8模型进行推理,通过DNN模块,之前本地的OpenCV版本是4.5.4(好像安装完ROS2 humble之后系统就自带了opencv),加载onnx模型一直报错,网上查询到需要4.7以上,干脆直接升…

vue3之依赖注入provide(提供)/inject(注入)

通常情况下,需要从父组件传值到子组件使用props足以,但是如果是深层嵌套的组件,如果某个深层的组件想要得到祖先组件的部分数据,使用props的话需要沿着各个嵌套的组件着层传递数据,而在传递过程中的组件压根就不需要使…

你了解 SpringBoot 在一次 http 请求中耗费了多少内存吗?

在实际工作中,经常会需要进行在全链路压测,优化 GC参数,优化 JVM 内存分配。 当知道 1 次 RPC 请求和 Http 请求需要的堆内存大小后,你可以精确地计算:指定的并发量之下,系统需申请多少堆内存。同时结合 J…

若依 根据角色权限 动态添加路由 学习

源于这个问题对若依权限改造的学习,用ASP.NET Core Web api 做后端,所以不是纯净的若依前端,有部分改过。 ​​​​​​​若依 从字典类型跳到字典数据跳到了404-CSDN博客 从路由守卫获取到用户信息开始,到路由跳转结束的过程 …

小猿搜题冲榜/刷排名/专用思路-理论速度1小时/3.6w分 附带0s教程

小猿搜题冲榜/刷排名/专用思路-理论速度1小时/3.6w分 附带0s教程 ⚠️:这个方法很多还需要手动操作,我目前无法用代码完全实现,如果你有兴趣可以给我提issue我们一起讨论。 冲榜思路 先说整体思路:抓包改答案adb模拟 之后详细…

10月更新|国内可用的ChatGPT攻略镜像中文网站

一、GPT中文镜像站 ① yixiaai.com 支持GPT4、4o以及o1,支持MJ绘画 ② chat.lify.vip 支持通用全模型,支持文件读取、插件、绘画、AIPPT ③ AI Chat支持GPT3.5/4,4o以及MJ绘画 1. 什么是镜像站 镜像站(Mirror Site&#xff0…

【GO基础学习】环境安装到基础语法(1)

文章目录 环境安装GoLand 安装GO基础GO特点类型和函数Init函数和main函数GO命令下划线变量和常量数组切片Slice 引用 环境安装 下载地址:https://www.golangroadmap.com/ 安装目录文件说明: api:每个版本的 api 变更差异。 bin&#xff1…

JAVA 字符串 trim() 方法的正确使用

JAVA类里面 trim() 方法大家都比较熟悉,就是用来清除掉字符串首尾的空白字符。但在一次程序运行崩溃后,查找具体原因时,发现是由字符串末尾的一个回车符号 "\r" 所导致的。于是有机会仔细读了下该方法的 java 文档说明。其中一段内…

Docker理念

1.为什么会出现Docker Docker 的出现并非偶然,而是由一系列技术发展趋势和实际需求所推动的一项技术创新。 随着软件行业的快速发展,开发团队的规模不断扩大,成员可能分布在不同的地理位置,使用不同的操作系统和开发工具。这就导致…

CSD(computational storage devices)架构介绍

CSD(computational storage devices)架构介绍 前言一、CSD与传统SSD的架构对比二、为什么要采用FPGA三、FPGA缺点四、个人总结reference 前言 虽然一直有接触CSD,但一直对其原理和架构知之甚少,半知不解。今天,趁着我还…

element-ui点击文字查看图片预览功能

今天做一个点击文字查看图片的功能&#xff0c;大体页面长这样子&#xff0c;点击查看显示对应的图片 引入el-image-viewer&#xff0c;点击的文字时候设置图片预览组件显示并传入图片的地址 关键代码 <el-link v-if"scope.row.fileList.length > 0" type&…

模型预测控制工具包——ACADO:简介、安装与测试

模型预测控制工具包——ACADO&#xff1a;简介、安装与测试 ACADO 工具包简介ubuntu20.04 安装 ACADO工具包安装依赖安装ACADOtoolkit 测试 ACADO 工具包简介 ACADO Toolkit 是一个用 C 编写的用于自动控制和动态优化的软件环境和算法集合。 它提供了一个通用框架&#xff0c;…

三菱FX3UPLC定位控制程序举例

测试程序的编写 1.输入输出的分配输入输出的分配如下表所示。 2、相关软元件的设定 相关软元件也有所不同。更改定位指令的脉冲输出端时&#xff0c;根因设定为定位指令的脉冲输出端的软元件不同&#xff0c;据更改的内容&#xff0c;需要变更设定的相关软元件。 3.程…

【大模型新书】掌握大语言模型:高级技术、应用、尖端方法和顶尖LLMs

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/93e5a5c008474f72a0335083ef9c4893.png)我已将 这本大模型书籍免费分享 出来&#xff0c;需要的小伙伴可以扫取。 主要特性 探索自然语言处理&#xff08;NLP&#xff09;基础和大语言模型基本原理&#xff0c;包括…