日常知识点之面试后反思裸写string类

1:实现一个字符串类。 简单汇总

最简单的方案,使用一个字符串指针,以及实际字符串长度即可。

参考stl的实现,为了提升string的性能,实际上单纯的字符串指针和实际长度是不够了,如上,有优化方案,除此之外,考虑reserve() 以及重置容量,迭代器的相关实现逻辑 (小字符串的存储优化,结合占用内存大小(4的倍数)分配适当的缓冲区更好)。

在这里插入图片描述

类中如果没有成员变量,类的大小为1,如果有成员变量,类的大小即为成员变量的大小。(以前研究过 sizeof(string)的长度 可能是28 或者32)

2:实现注意细节

1:c字符串指针+ 实际字符串的长度进行数据存储

2:内存的申请和释放 用new/delete 或者malloc/free都可以吧, 字符串的赋值借用strcpy 或者memcpy都可以吧。

3:默认构造函数 c字符串传参构造 拷贝构造(深拷贝) 移动构造(浅拷贝 std::move) 赋值复制构造 赋值移动构造(右参std::move)

4:注意整个过程中 const参数的修饰,以及相关函数返回值 返回引用对象和返回对象。

5:重载必要的运算符(+ = == ),输入输出的重载(<< >>),注意重载<<和>>时和friend关键字配合,以及实现细节。

6:c字符串相关函数(strcpy strcmp strlen strcat strchr

在这里插入图片描述

3:源码测试

3.1 类的声明(思考const,noexcept修饰,复制传参,引用传参,以及返回值返回引用 返回对象)

/*************************************
1:不需要考虑太多,直接字符串指针和长度进行实现。
2:考虑该类的大小,如果字符串为null时,如果字符串有长度时。 (字符串拼接  截断等)
3:字符串性能的优化,短字符串直接存栈中,长的进行申请。  其他考虑迭代器等的实现方案。只考虑指针和长度进行实现:1:默认构造函数。2:C字符串初始化,直接初始化,移动构造。   拷贝构造函数,赋值构造函数。3:重载运算符 = == + << >> +=
**************************************/
#include <iostream>
#include <cstring>#include <stdio.h>
class my_string
{
private:char* data;size_t length;public://默认构造函数 c字符串构造  拷贝构造函数 移动构造函数  赋值构造函数 my_string();my_string(const char* str);my_string(const my_string& other);my_string(my_string&& other) noexcept;~my_string();size_t size() const;const char* c_str() const;//=  ==  +  <<my_string& operator = (const my_string& other) noexcept; //赋值构造函数 复制my_string& operator = (my_string&& other) noexcept;  //移动赋值构造函数bool  operator==(const my_string& other) const;my_string operator +(const my_string& other) const;
//注意friend的定义friend std::ostream& operator<<(std::ostream& os, const my_string& str);friend std::istream& operator>>(std::istream& in, my_string& str); //输入需要可修改
};

3.2 类的定义

//函数前面用const 表示的是函数返回值const
//函数后面用用const修饰 可以使常量调用,表示该函数内部不可以修改成员变量 
my_string::my_string() :data(nullptr), length(0)
{printf("my_string() \n");data = new char[1];data[0] = '\0';
}//c字符串对string进行初始化  c字符串为NULL 不为NULL  
//以及c字符串本身也是一以\0终止
my_string::my_string(const char* str)
{printf(" my_string(const char * str) = %s \n", str);if (str){length = strlen(str); //str为NULL  会导致抛异常 data = new char[length + 1];strcpy(data, str);}else{data = new char[1];data[0] = '\0';length = 0;}
}//字符串之间 拷贝构造函数 使用传递引用的方式提升性能 
//在自己类的成员函数中   参数可以直接访问私有成员
my_string::my_string(const my_string& other)
{printf(" my_string(const my_string & str) = %s \n", other.data);length = other.length;data = new char[length + 1];strcpy(data, other.data);
}//移动构造函数  注意&&  浅拷贝
my_string::my_string(my_string&& other) noexcept
{printf(" my_string(my_string && str) = %s \n", other.data);//不用申请内存 直接进行赋值即可data = other.data;length = other.length;other.data = nullptr;other.length = 0;
}my_string::~my_string()
{printf("~my_string() = %s \n", data);if(data)delete[]data;
}size_t my_string::size() const
{return length;
}const char* my_string::c_str() const
{return data;
}//=  ==  +  <<
//深拷贝 注意对象可能同一个   返回对象的引用  
my_string& my_string::operator = (const my_string& other) noexcept//赋值构造函数 复制
{printf("operator = (const my_string & other) = %s \n", other.data);if (this == &other){return *this;}//赋值 先清理 再赋值delete[]data;length = other.length;data = new char[length + 1];strcpy(data, other.data);return *this;
}//浅拷贝  注意对象可能一个 返回引用
my_string& my_string::operator = (my_string&& other) noexcept //移动赋值构造函数
{printf("operator = (my_string && other) = %s \n", other.data);if (this == &other){return *this;}data = other.data;length = other.length;other.data = nullptr;other.length = 0;return *this;  //返回对象的引用  
}//判断两个字符串相等 
bool  my_string::operator==(const my_string& other) const
{printf("operator==(const my_string &other) = %s \n", other.data);return strcmp(data, other.data) == 0;
}my_string my_string::operator +(const my_string& other) const
{printf("operator +(const my_string & other) = %s \n", other.data);my_string NewString;NewString.length = length + other.length;NewString.data = new char[NewString.length + 1];strcpy(NewString.data, data);strcpy(NewString.data, other.data);return NewString; //函数中定义的对象   返回该拷贝
}

注意operator<< 和operator>>和friend的细节。

//输出 
std::ostream& operator <<(std::ostream& os, const my_string& str)
{os << str.data;return os;
}
std::istream& operator>>(std::istream& in,  my_string& str)
{//或者按行输入获取字符串const size_t BUFFER_SIZE = 1024;char buffer[BUFFER_SIZE] = { 0 };in >> buffer;str.length = strlen(buffer);delete[] str.data; //理论上都是已有对象进行输入 str.data = new char[str.length + 1];strcpy(str.data, buffer);return in;
}

3.3 测试代码

int main()
{//默认构造函数测试my_string str; //默认构造函数my_string str_c("c string");  //c字符串构造my_string str_str(str_c);   //拷贝构造吧printf("size = %d dara = %s \n", str_str.size(), str_str.c_str());my_string str_move(std::move(str_str)); //移动语义if (str_str.c_str() == nullptr){printf("size = %d dara = nullptr \n", str_str.size());}printf("size = %d dara = %s \n", str_move.size(), str_move.c_str());std::cout << "\nos =" << str_move << std::endl;
//直接初始化 my_string str_move1 = std::move(str_move);std::cout << "\nstr_move1  =" << str_move1 << std::endl;//std::cout << "\nstr_move  =" << str_move << std::endl;//赋值构造my_string str_cp = str_move1;std::cout << "\nstr_move1 =" << str_move1 << std::endl;std::cout << "\nstr_cp =" << str_cp << std::endl;
//赋值初始化 my_string str_cp_by_operator;my_string str_move_by_operator;str_cp_by_operator = str_cp;std::cout << "\nstr_cp_by_operator =" << str_cp_by_operator << std::endl;std::cout << "str_cp =" << str_cp << std::endl;str_move_by_operator = std::move(str_cp);std::cout << "\nstr_move_by_operator =" << str_cp_by_operator << std::endl;if (str_cp.c_str() != nullptr){std::cout << "str_cp =" << str_cp << std::endl;}if (str_cp_by_operator == str_move_by_operator){printf("\n operator ==  is success! \n");}else{printf("\n operator ==  is failed! \n");}my_string add = str_cp_by_operator + str_move_by_operator;std::cout << "add =" << add << std::endl;printf("please input str:==>");std::cin >> str;std::cout << "os =" << str << std::endl;return 0;
}

3.4:结合结果分析:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用AI绘制CAD气温曲线图

此文章视频讲解地址 https://www.bilibili.com/video/BV1JtKjenEhF 需求 根据气温的JSON数据&#xff0c;用AI自动生成CAD格式的气温曲线DWG图 数据准备 用deepseek获取了北京市最近一个月的气温json数据 AI对话 首先进入唯杰地图云端管理平台 选择与唯杰地图AI对话 需求描…

Web应用项目开发 ——Spring Boot邮件发送

一.邮件发送介绍 邮件发送是一个非常常见的功能&#xff0c;注册时的身份认证、重要通知发送等都会用到邮件发送。在现代的Web应用程序中&#xff0c;邮件发送功能是非常常见且重要的一部分&#xff0c;Spring Boot框架提供了简单且强大的方式来实现邮件发送功能。Spring中提供…

【STM32】通过L496的HAL库Flash建立FatFS文件系统(CubeMX自动配置R0.12C版本)

【STM32】通过L496的HAL库Flash建立FatFS文件系统&#xff08;CubeMX自动配置R0.12C版本&#xff09; 文章目录 FlashFlash地址写Flash地址读 FatFS文件系统配置FatFS移植驱动函数时间戳函数 文件操作函数工作区缓存文件挂载和格式化测试文件读写测试其他文件操作函数 测试附录…

机械臂运动学笔记(一):正向运动学

正向运动学指的是通过相邻关节间的转动和移动坐标&#xff0c;将末端的坐标计算出来。 反向运动学指的是已知机械臂末端的坐标&#xff0c;反算每个关节可能的转动和移动参数。 参考资料&#xff1a;4.机械臂几何法与DH表示法_哔哩哔哩_bilibili 一.任意连杆连接的变量定义&a…

Leetcode - 周赛435

目录 一、3442. 奇偶频次间的最大差值 I二、3443. K 次修改后的最大曼哈顿距离三、3444. 使数组包含目标值倍数的最少增量四、3445. 奇偶频次间的最大差值 II 一、3442. 奇偶频次间的最大差值 I 题目链接 本题使用数组统计字符串 s s s 中每个字符的出现次数&#xff0c;然后…

鸿蒙HarmonyOS NEXT开发:优化用户界面性能——组件复用(@Reusable装饰器)

文章目录 一、概述二、原理介绍三、使用规则四、复用类型详解1、标准型2、有限变化型2.1、类型1和类型2布局不同&#xff0c;业务逻辑不同2.2、类型1和类型2布局不同&#xff0c;但是很多业务逻辑公用 3、组合型4、全局型5、嵌套型 一、概述 组件复用是优化用户界面性能&#…

pyrender 渲染报错解决

pyrender渲染后&#xff0c;出来的图样子不对&#xff1a; 正确的图&#xff1a; 解决方法&#xff1a; pip install numpy1.26 下面的不是必须的&#xff1a; pip install pyrender0.1.45 os.environ["PYOPENGL_PLATFORM"] "egl" os.environ[EGL_DEVI…

CCFCSP第34次认证第一题——矩阵重塑(其一)

第34次认证第一题——矩阵重塑&#xff08;其一&#xff09; 官网链接 时间限制&#xff1a; 1.0 秒 空间限制&#xff1a; 512 MiB 相关文件&#xff1a; 题目目录&#xff08;样例文件&#xff09; 题目背景 矩阵&#xff08;二维&#xff09;的重塑&#xff08;reshap…

Neurlps2024论文解读|BERTs are Generative In-Context Learners-water-merged

论文标题 BERTs are Generative In-Context Learners BERTs 是生成式上下文学习器 论文链接 BERTs are Generative In-Context Learners论文下载 论文作者 David Samuel 内容简介 本文探讨了掩码语言模型&#xff08;如DeBERTa&#xff09;在上下文学习中的生成能力&…

深入理解Java对接DeepSeek

其实&#xff0c;整个对接过程很简单&#xff0c;就四步&#xff0c;获取key&#xff0c;找到接口文档&#xff0c;接口测试&#xff0c;代码对接。 1.获取 KEY https://platform.deepseek.com/transactions 直接付款就是了&#xff08;现在官网暂停充值2025年2月7日&#xf…

OSPF高级特性(3):安全特效

引言 OSPF的基础我们已经结束学习了&#xff0c;接下来我们继续学习OSPF的高级特性。为了方便大家阅读&#xff0c;我会将高级特性的几篇链接放在末尾&#xff0c;所有链接都是站内的&#xff0c;大家点击即可阅读&#xff1a; OSPF基础&#xff08;1&#xff09;&#xff1a;工…

HCIA项目实践--静态路由的总结和简单配置

七、静态路由 7.1 路由器获取未知网段的路由信息&#xff1a; &#xff08;1&#xff09;静态路由&#xff1a;网络管理员手工配置的路由条目&#xff0c;它不依赖网络拓扑的变化进行自动更新&#xff0c;而是根据管理员预先设定的路径来转发数据包。其优点是配置简单、占用系…

3dtiles——Cesium ion for Autodesk Revit Add-In插件

一、说明&#xff1a; Cesium已经支持3dtiles的模型格式转换&#xff1b; 可以从Cesium官方Aesset中上传gltf等格式文件转换为3dtiles&#xff1b; 也可以下载插件&#xff08;例如revit-cesium插件&#xff09;转换并自动上传到Cesium官方Aseet中。 Revit转3dtiles插件使用…

HCIA项目实践---网络层次常见的三种模型

2.2 网络的层次 2.2.1 常见的三种网络层次划分 应用层 &#xff08;1&#xff09;OSI 七层模型 物理层&#xff1a;处于最底层&#xff0c;主要负责处理物理介质上的信号传输&#xff0c;如电缆、光纤、无线等。其作用是定义物理设备的接口标准、信号的编码方式、传输速率等&…

【图片转换PDF】多个文件夹里图片逐个批量转换成多个pdf软件,子文件夹单独合并转换,子文件夹单独批量转换,基于Py的解决方案

建筑设计公司在项目执行过程中&#xff0c;会产生大量的设计图纸、效果图、实景照片等图片资料。这些资料按照项目名称、阶段、专业等维度存放在多个文件夹和子文件夹中。 操作需求&#xff1a;为了方便内部管理和向客户交付完整的设计方案&#xff0c;公司需要将每个项目文件…

Python:凯撒密码

题目内容&#xff1a; 凯撒密码是古罗马恺撒大帝用来对军事情报进行加密的算法&#xff0c;它采用了替换方法对信息中的每一个英文字符循环替换为字母表序列该字符后面第三个字符&#xff0c;对应关系如下&#xff1a; 原文&#xff1a;A B C D E F G H I J K L M N O P Q R …

亚信安全正式接入DeepSeek

亚信安全致力于“数据驱动、AI原生”战略&#xff0c;早在2024年5月&#xff0c;推出了“信立方”安全大模型、安全MaaS平台和一系列安全智能体&#xff0c;为网络安全运营、网络安全检测提供AI技术能力。自2024年12月DeepSeek-V3发布以来&#xff0c;亚信安全人工智能实验室利…

2024BaseCTF_week4_web上

继续&#xff01;冲冲冲 目录 圣钥之战1.0 nodejs 原型 原型链 原型链污染 回到题目 flag直接读取不就行了&#xff1f; 圣钥之战1.0 from flask import Flask,request import jsonapp Flask(__name__)def merge(src, dst):for k, v in src.items():if hasattr(dst, __geti…

【Java 面试 八股文】Redis篇

Redis 1. 什么是缓存穿透&#xff1f;怎么解决&#xff1f;2. 你能介绍一下布隆过滤器吗&#xff1f;3. 什么是缓存击穿&#xff1f;怎么解决&#xff1f;4. 什么是缓存雪崩&#xff1f;怎么解决&#xff1f;5. redis做为缓存&#xff0c;mysql的数据如何与redis进行同步呢&…

使用 Dockerfile 构建自定义 Nginx 镜像并集成 nginx_upstream_check_module

目录 1. 为什么需要自定义 Nginx 镜像&#xff1f; 2. Dockerfile 解析 2.1 基础镜像选择 2.2 安装依赖 2.3 下载并解压 Nginx 源码 2.4 应用补丁并编译 Nginx 2.5 暴露端口并设置启动命令 3. 构建并运行自定义 Nginx 镜像 3.1 构建镜像 3.2 运行容器 3.3 健康检测配…