当前位置: 首页 > news >正文

C++——string的模拟实现(上)

目录

引言

成员变量

1.基本框架

成员函数

1.构造函数和析构函数

2.拷贝构造函数

3.容量操作函数

3.1 有效长度和容量大小

3.2 容量操作

3.3 访问操作

(1)operator[]函数

(2)iterator迭代器

3.4 修改操作

(1)push_back()和append()

(2)operator+=函数


引言

在 C++——string的了解和使用 中,我们学习了string的一些基础用法。接下来我们可以试着模拟实现string。

在C++中,std::string是一个功能强大且广泛使用的类,用于处理字符串。然而,了解其内部实现原理对于深入理解C++和编写高效代码至关重要。通过模拟实现一个简单的string类,我们可以更好地理解字符串的存储、管理以及操作。这不仅有助于我们更好地使用std::string,还能让我们在遇到特定需求时,能够自定义字符串类来满足这些需求。

成员变量

1.基本框架

为了与STL库中的string区分开来,我们要使用命名空间namespace进行封装。

char* _str:指向字符数组的指针,用于存储字符串的实际内容。

size_t  _size:表示字符串中有效字符的数量。

size_t  _capacity:表示字符数组的容量,即可以存储的最大字符数量(包括结尾的空字符\0)。

namespace My_string
{class string {public:// ...private:char* _str;size_t _size;size_t _capacity;};
}

成员函数

老规矩,我们在 string.h 中,声明函数;在 string.cpp 中,实现函数的功能。

1.构造函数和析构函数

构造函数:接受一个C风格字符串作为参数,计算其长度,分配足够的内存来存储该字符串及其结尾的空字符,并复制字符串内容。

析构函数:释放分配给字符串的内存,并将指针设置为nullptr,以避免悬挂指针问题。同时,将_size和_capacity设置为0,表示对象已销毁。

string.h:

namespace My_string
{class string {public:string(const char* str);//构造函数~string();				//析构函数private:char* _str;size_t _size;size_t _capacity;};
}

string.cpp:

#include"string.h"
namespace My_string
{// 构造函数string::string(const char* str){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];    // +1用于储存'\0'strcpy(_str, str);}// 析构函数string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}
}

我们可以测试一下:

通过调试观察一下:

调用构造函数:

调用析构函数:

2.拷贝构造函数

拷贝构造函数:接受一个string对象作为参数,分配足够的内存来存储原对象的字符串内容,并复制该内容。

这里提供了三种实现方式,包括直接复制、使用临时对象进行深拷贝以及使用swap函数进行资源转移。

string.h:

string(const string& str);		//拷贝构造函数

string.cpp:

// 拷贝构造函数(1)
string::string(const string& str)
{_str = new char[str._capacity + 1];	//额外多给一个空间,用于存放'/0'strcpy(_str, str._str);		//拷贝数据_capacity = str._capacity;	//设置容量_size = str._size;			//设置有效数据个数
}

我们在这里也有其他的方法可以实现拷贝构造:

// 拷贝构造函数(2)
string::string(const string& str)
{string tmp(str._str);std::swap(tmp._str, _str);std::swap(tmp._size, _size);std::swap(tmp._capacity, _capacity);
}

以上代码还可以接着简化:

string::string(const string& str)
{string tmp(str._str);swap(tmp);			// 这里的swap我们接下来会定义
}

3.容量操作函数

3.1 有效长度和容量大小

我们先写这两个函数:

size()和capacity():分别返回字符串的有效长度和字符数组的容量。

string.h:

		size_t size() const;			// size()函数size_t capacity() const;		// capacity()函数

string.cpp:

// size()函数
size_t string::size() const
{return _size;
}// capacity()函数
size_t string::capacity() const
{return _capacity;
}
3.2 容量操作

c_str():返回一个指向以空字符结尾的字符数组的指针,该数组包含与string对象相同的字符序列。这允许将string对象与接受C风格字符串的函数一起使用。

empty():检查字符串是否为空(即长度为0)。

erase():删除字符串中指定位置的字符或子字符串。

string.h:

const char* c_str() const;		// c_str()函数
bool empty() const;				// empty()函数
void erase(size_t pos = 0, size_t len = npos);    // erase()函数

string.cpp:

// c_str()函数
const char* string::c_str() const
{return _str;
}
// empty()函数
bool string::empty() const
{return _size == 0;
}
// erase()函数
void string::erase(size_t pos,size_t len)
{assert(pos < _size);				 if (len == npos || len >= _size - pos){_str[pos] = '\0';		// 位置pos置为'\0'_size = pos;			// 有效元素个数为pos个}else	// len小于后面的字符个数{// 将后面的字符拷贝到pos位置strcpy(_str + pos, _str + pos + len);_size -= len;			// 更新有效元素}
}

接下来再来实现扩容函数reserve()和resize():

reserve():增加字符数组的容量,以确保可以存储至少n个字符。如果当前容量不足,则分配新的内存并复制现有内容。

resize():改变字符串的大小。如果新大小大于当前大小,则添加新字符(默认为\0);如果新大小小于当前大小,则删除多余的字符。

string.h:

// 预留空间
void reserve(size_t n);
// resize()函数
void resize(size_t n, char ch = '\0');

string.cpp:

// 预留空间
void string::reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}
}
// resize()函数
void string::resize(size_t n, char ch)
{if (n > _size){if (n > _capacity){reserve(n);}// 使用 memset 函数将字符 ch // 填充到新添加的空间中memset(_str + _size, ch, n - _size);}_size = n;_str[n] = '\0';
}
3.3 访问操作
(1)operator[]函数

operator[]函数的功能:返回pos位置的字符

string.h:

// 非const版本
char& operator[](size_t pos);	//operator[]函数
// const版本
const char& operator[](size_t pos)const;

string.cpp:

// operator[]函数
char& string::operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}
// const版本
const char& string::operator[](size_t pos)const
{assert(pos < _size);return _str[pos];
}

来个简单的代码测试一下:

(2)iterator迭代器

迭代器:提供begin()和end()函数来返回指向字符串开头和结尾的迭代器。这里简化了迭代器的实现,将其视为指向字符数组的指针。然而,在实际应用中,迭代器通常是一个更复杂的类,提供了更多的功能和安全性检查。

string.h:

//const版本的iterator
const_iterator begin() const;	//提供const_iterator begin()函数
const_iterator end() const;		//提供const_iterator end()函数//非const版本的iterator
iterator begin();				//提供iterator begin()函数
iterator end();					//提供iterator end()函数

string.cpp:

string::iterator string::begin()
{return _str;
}
string::iterator string::end()
{return _str + _size;
}
string::const_iterator string::begin() const
{return _str;
}
string::const_iterator string::end() const
{return _str + _size;
}

还是老样子,我们使用一个简单的函数测试一下:

void test3()
{My_string::string str("hello");for (auto i : str){cout << i << " ";}cout << endl;My_string::string::iterator it1 = str.begin();while (it1 != str.end()){cout << *it1 << " ";++it1;}cout << endl;My_string::string::iterator it2 = str.end();if (it2 != str.begin()) { // 检查避免直接解引用 end()  --it2; // 先移动到一个有效的位置  while (it2 != str.begin()){std::cout << *it2 << " ";--it2;}std::cout << *it2 << " "; // 输出最后一个字符(begin() 之前的字符)  }std::cout << std::endl;
}

输出结果为:

3.4 修改操作
(1)push_back()和append()

string.h:

// 尾插一个字符
void push_back(char ch);
// 尾插一个字符串
void append(const char* str);

string.cpp:

//尾插一个字符
void string::push_back(char ch)
{if (_capacity == _size){size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';_size++;
}//尾插一个字符串
void string::append(const char* str)
{size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}strcpy(_str+_size, str);_size += len;			
}
(2)operator+=函数

我们可以借助上面两个函数实现operator+=函数。

string.h:

//operator+=函数可以构成重载,函数名相同,参数不同
string& operator+=(char ch);			// 字符相加
string& operator +=(const char* str);	// 字符串相加

string.cpp:

string& string::operator+=(char ch)
{// 调用push_back()函数push_back(ch);		return *this;
}
string& string::operator+=(const char* str)
{append(str);return *this;
}

来测试一下:

operator+=函数返回的是对象本身。

内置类型的+=运算符返回值的副本。

自定义类型的+=运算符通常返回对象的引用(即*this),以支持链式操作和避免复制。

———————————————————————————————————————————

以上为string模拟实现的第一篇

求点赞收藏评论关注!!!

感谢各位大佬!!!

第二篇链接:C++——string的模拟实现(下)

相关文章:

C++——string的模拟实现(上)

目录 引言 成员变量 1.基本框架 成员函数 1.构造函数和析构函数 2.拷贝构造函数 3.容量操作函数 3.1 有效长度和容量大小 3.2 容量操作 3.3 访问操作 (1)operator[]函数 (2)iterator迭代器 3.4 修改操作 (1)push_back()和append() (2)operator函数 引言 在 C—…...

JavaCV 之均值滤波:图像降噪与模糊的权衡之道

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…...

桥接模式,外界与主机通,与虚拟机不通

一 二 在此选择Windows与外界连接的网卡&#xff0c;通过有线连就选有线网卡&#xff0c;通过无线连就选无线网卡。 三 如果需要设置固定IP&#xff0c;则选择"Manual"进行设置。我这边根据实际需要&#xff0c;走无线的时候用DHCP&#xff0c;走有线的时候设固定IP…...

用HTML构建酷炫的文件上传下载界面

1. 基础HTML结构 首先&#xff0c;我们构建一个基本的HTML结构&#xff0c;包括一个表单用于文件上传&#xff0c;以及一个列表用于展示已上传文件&#xff1a; HTML <!DOCTYPE html> <html> <head><title>酷炫文件上传下载</title><link …...

Gateway 统一网关

一、初识 Gateway 1. 为什么需要网关 我们所有的服务可以让任何请求访问&#xff0c;但有些业务不是对外公开的&#xff0c;这就需要用网关来统一替我们筛选请求&#xff0c;它就像是房间的一道门&#xff0c;想进入房间就必须经过门。而请求想要访问微服务&#xff0c;就必须…...

7 种常见的前端攻击

大家都知道&#xff0c;保证网站的安全是十分重要的&#xff0c;一旦网站被攻陷&#xff0c;就有可能造成用户的经济损失&#xff0c;隐私泄露&#xff0c;网站功能被破坏&#xff0c;或者是传播恶意病毒等重大危害。所以下面我们就来讲讲7 种常见的前端攻击。 1. 跨站脚本 (X…...

element plus实现点击上传于链接上传并且回显到upload组件中

摘要&#xff1a; 今天遇到一个问题&#xff1a;vue3使用elemnt plus的上传图片时&#xff0c;数据是从别人的系统导出来的商品&#xff0c;图片是http的形式的&#xff0c;并且商品很多的&#xff0c;一个一个下载下来再上传很麻烦的&#xff0c;所以本系统插件商品时图片使用…...

ELK日志分析系统部署

ELK日志分析系统 ELK指的是ElasticsearchLogstashKibana这种架构的缩写。 ELK是一种日志分析平台&#xff0c;在很早之前我们经常使用Shell三剑客&#xff08;一般泛指grep、sed、awk&#xff09;来进行日志分析&#xff0c;这种方式虽然也可以应对多种场景&#xff0c;但是当…...

驾校小程序:一站式学车解决方案的设计与实践

​​一、引言 随着移动互联网技术的飞速发展&#xff0c;人们的生活方式和消费习惯正在发生深刻变化。驾校作为传统的服务行业&#xff0c;也面临着数字化转型的迫切需求。驾校小程序作为一种轻量级的应用&#xff0c;能够为用户提供便捷、丰富的学车服务&#xff0c;成…...

【自然语言处理】BERT模型

BERT&#xff1a;Bidirectional Encoder Representations from Transformers BERT 是 Google 于 2018 年提出的 自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;它基于 Transformer 架构的 Encoder 部分。BERT 的出现极大提升了 NLP 任务的性能&#xff0c;如问答系…...

Android 添加如下飞行模式(飞行模式开和关、飞行模式开关菜单显示隐藏)接口

请添加如下飞行模式(飞行模式开关、飞行模式开关显示隐藏)接口: 飞行模式飞行模式开关com.action.airplankey: enable value:boolean true open the airplan false close the airplan关闭Intent intent = new Intent(); intent.setAction("com.action.airplan");…...

【Vue3】基于 Vue3 + ECharts 实现北京市区域地图可视化

文章目录 基于 Vue3 ECharts 实现北京市区域地图可视化1、引言2、项目初始化2.1、环境搭建2.2 、安装依赖2.3、项目结构 3、地图数据准备3.1、地图 JSON 文件获取&#xff08;具体的json数据&#xff09; 4、 组件开发4.1、Map 组件的设计思路4.2、基础结构实现4.3、核心数据结…...

【IC】什么是min period check

在 Synopsys Primetime 工具中可以检查.lib 文件中时钟输入的最小周期。想象这样一个场景&#xff0c;有一个设计 A&#xff0c;它有一个名为 clk 的时钟&#xff0c;并且该设计的 clk 周期被设定为一个值&#xff0c;比如 2 纳秒&#xff0c;即 500MHz。假设我们在进行静态时序…...

MyBatis入门之一对多关联关系(示例)

【图书介绍】《SpringSpring MVCMyBatis从零开始学&#xff08;视频教学版&#xff09;&#xff08;第3版&#xff09;》-CSDN博客 《SpringSpring MVCMyBatis从零开始学(视频教学版)&#xff08;第3版&#xff09;》(杨章伟&#xff0c;刘祥淼)【摘要 书评 试读】- 京东图书 …...

【Git 】Windows 系统下 Git 文件名大小写不敏感

背景 在 Windows 系统上&#xff0c;Git 对文件名大小写的不敏感性问题确实存在。由于 Windows 文件系统&#xff08;如 NTFS &#xff09;在默认情况下不区分文件名大小写所导致的。 原因分析 文件系统差异 Windows文件系统&#xff08;如 NTFS&#xff09;默认不区分文件名…...

【算法系列-二叉树】层序遍历

【算法系列-二叉树】层序遍历 文章目录 【算法系列-二叉树】层序遍历1. 算法分析&#x1f6f8;2. 相似题型&#x1f3af;2.1 二叉树的层序遍历II(LeetCode 107)2.2 二叉树的右视图(LeetCode 199)2.3 二叉树的层平均值(LeetCode 637)2.4 N叉树的层序遍历(LeetCode 429)2.5 在每个…...

我的世界方块改进版

引子 之前文章的磁性方块&#xff0c;通过3D打印实现&#xff0c;也批量打印了一些&#xff0c;下图就是一个小树 使用过程中&#xff0c;发现磁力感觉不紧&#xff0c;所以想改进一版。 正文 之前的结构如下&#xff1a;&#xff1a; 如果出现相邻的空隙间的磁铁相互作用&am…...

博客搭建之路:hexo增加搜索功能

文章目录 hexo增加搜索功能本地搜索弊端algolia搜索 hexo增加搜索功能 hexo版本5.0.2 npm版本6.14.7 next版本7.8.0 作为一个博客&#xff0c;没有搜索功能&#xff0c;如何在大批文章中找到自己想要的&#xff0c;那在hexo中如何增加搜索功能呢&#xff1f; search:path: sea…...

2024年最新互联网大厂精选 Java 面试真题集锦(JVM、多线程、MQ、MyBatis、MySQL、Redis、微服务、分布式、ES、设计模式)

前言 春招&#xff0c;秋招&#xff0c;社招&#xff0c;我们 Java 程序员的面试之路&#xff0c;是挺难的&#xff0c;过了 HR&#xff0c;还得被技术面&#xff0c;在去各个厂面试的时候&#xff0c;经常是通宵睡不着觉&#xff0c;头发都脱了一大把&#xff0c;还好最终侥幸…...

MybatisPlus入门(一)MybatisPlus简介

一、MyBatis简介 MyBatisPlus&#xff08;简称MP&#xff09;是基于MyBatis框架基础上开发的增强型工具&#xff0c;旨在简化开发、提高效率 - 官网&#xff1a;https://mybatis.plus/ https://mp.baomidou.com/ MyBatisPlus特性&#xff1a; - 无侵入&#xff1a;只做增强…...

CANN/Ascend C逻辑异或API文档

LogicalXor 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言&#xff0c;原生支持C和C标准规范&#xff0c;主要由类库和语言扩展层构成&#xff0c;提供多层级API&#xff0c;满足多维场景算子开发诉求。 项目地址: https://gitcode.com…...

联发科2012年崛起:从功能机到智能机的转型与挑战

1. 从功能机到智能机的惊险一跃&#xff1a;联发科的2012年2012年&#xff0c;对于全球移动芯片行业来说&#xff0c;是几家欢喜几家愁的一年。诺基亚和黑莓的持续衰落&#xff0c;直接拖垮了像ST-Ericsson这样深度绑定的芯片供应商&#xff1b;即便是巨头如高通&#xff0c;也…...

开源技能图谱平台gotalab/skillport:构建可视化知识大脑的实战指南

1. 项目概述&#xff1a;一个技能图谱与知识管理的开源利器 在信息爆炸的时代&#xff0c;无论是个人学习成长&#xff0c;还是团队知识沉淀&#xff0c;我们常常面临一个核心痛点&#xff1a; 知识是零散的、孤立的&#xff0c;难以形成体系&#xff0c;更难以高效复用 。你…...

kagent:把 Agent 当 Pod 来管,赌的是 Agent 的最终归宿是 K8s

我们写过用 kubectl apply -f deployment.yaml 起一个 Pod&#xff0c;写过用 Service 把它暴露出来&#xff0c;写过用 Operator 监听 CRD 自动调和状态。Solo.io 那群人 2025 年初做了一个看起来很自然、但没人提早做出来的事&#xff1a;把同一套思路平移到 AI Agent 上——…...

深入STM32以太网驱动层:DP83848 PHY芯片初始化、中断处理与lwip数据收发的HAL库实现详解

STM32与DP83848以太网驱动开发实战&#xff1a;从PHY初始化到lwIP协议栈深度整合 在嵌入式系统开发中&#xff0c;以太网通信已成为工业控制、物联网网关等场景的标配功能。本文将深入探讨基于STM32F1系列微控制器与DP83848物理层芯片的以太网驱动开发全流程&#xff0c;重点剖…...

奇点大会「隐形议程」住宿推荐:主办方未公布的3家闭门交流友好型酒店(含私密会议室共享权限与静音舱预约入口)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;奇点智能技术大会周边酒店推荐 参会者抵达主办城市后&#xff0c;便捷、稳定且具备基础协作设施的住宿环境至关重要。以下推荐均基于步行至主会场&#xff08;国家人工智能创新中心&#xff09;≤15分钟…...

Flutter for OpenHarmony 代码片段收藏夹APP技术文章

Flutter for OpenHarmony 代码片段收藏夹APP技术文章 欢迎加入开源鸿蒙跨平台社区&#xff1a;https://openharmonycrossplatform.csdn.net &#x1f680; Flutter for OpenHarmony 实战&#xff1a;打造开发者专属代码片段收藏夹 APP 哈喽各位开发者小伙伴们&#xff01;今…...

PyCharm直连Spark集群:一站式配置与避坑指南

1. 为什么需要PyCharm直连Spark集群&#xff1f; 作为数据工程师&#xff0c;我经常需要在本地开发Spark应用&#xff0c;然后部署到远程集群执行。传统方式是本地写完代码后&#xff0c;手动上传到服务器再用spark-submit提交&#xff0c;这个过程既繁琐又容易出错。直到发现P…...

Gemini3.1Pro如何实现视觉平移不变性

“视觉 Transformer 的平移不变性&#xff08;translation invariance&#xff09;是否能在 Gemini 3.1 Pro 中实现&#xff1f;”这个问题的难点在于&#xff1a;平移不变性是视觉模型的归纳偏置&#xff0c;而 Gemini 3.1 Pro 是多模态大模型&#xff08;LLM视觉/多模态能力&…...

终极指南:如何用NPYViewer快速查看和可视化NumPy数组数据

终极指南&#xff1a;如何用NPYViewer快速查看和可视化NumPy数组数据 【免费下载链接】NPYViewer Load and view .npy files containing 2D and 1D NumPy arrays. 项目地址: https://gitcode.com/gh_mirrors/np/NPYViewer 还在为NumPy数组数据查看而烦恼吗&#xff1f;当…...