日常知识点之面试后反思裸写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.mzph.cn/web/69699.shtml

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

相关文章

phpipam1.7安装部署

0软件说明 phpipam是一个开源Web IP地址管理应用程序&#xff08;IPAM&#xff09; phpipam官网&#xff1a;https://www.phpipam.net/ 1安装环境 操作系统&#xff1a;Rocky Linux9.5x86_64 phpipam版本&#xff1a;1.7 php版本&#xff1a;8.0.30 数据库版本&#xff1a…

python卷积神经网络人脸识别示例实现详解

目录 一、准备 1&#xff09;使用pytorch 2&#xff09;安装pytorch 3&#xff09;准备训练和测试资源 二、卷积神经网络的基本结构 三、代码实现 1&#xff09;导入库 2&#xff09;数据预处理 3&#xff09;加载数据 4&#xff09;构建一个卷积神经网络 5&#xff0…

网络安全总结

网络安全总结 网络安全第一篇 &#xff11;. 防火墙必不可少(局域网与互联网之间必须隔离) 连接到Internet的每一个人都需要在其网络入口处采取一定的措施來阻止和丢弃恶意的网络通信,但是我们貌似没有这么做&#xff0c;这就需要我们在物理或者软件实现我们的防火墙&#xf…

【文本处理】如何在批量WORD和txt文本提取手机号码,固话号码,提取邮箱,删除中文,删除英文,提取车牌号等等一些文本提取固定格式的操作,基于WPF的解决方案

企业的应用场景 数据清洗&#xff1a;在进行数据导入或分析之前&#xff0c;往往需要对大量文本数据进行预处理&#xff0c;比如去除文本中的无关字符&#xff08;中文、英文&#xff09;&#xff0c;只保留需要的联系信息&#xff08;手机号码、固话号码、邮箱&#xff09;。…

【Cocos TypeScript 零基础 15.1】

目录 见缝插针UI脚本针脚本球脚本心得_旋转心得_更改父节点心得_缓动动画成品展示图 见缝插针 本人只是看了老师的大纲,中途不明白不会的时候再去看的视频 所以代码可能与老师代码有出入 SIKI_学院_点击跳转 UI脚本 import { _decorator, Camera, color, Component, directo…

pdf.js默认显示侧边栏和默认手形工具

文章目录 默认显示侧边栏(切换侧栏)默认手形工具(手型工具) 大部分的都是在viewer.mjs中的const defaultOptions 变量设置默认值,可以使用数字也可以使用他们对应的变量枚举值 默认显示侧边栏(切换侧栏) 在viewer.mjs中找到defaultOptions,大概在732行,或则搜索sidebarViewOn…

基于 ollama 在linux 私有化部署DeepSeek-R1以及使用RESTful API的方式使用模型

由于业务需求部署的配置 deepseek:32b,linux配置GPU L20 4卡 ,SSD 200g&#xff0c;暂未发现有什么问题&#xff0c;持续观察中 ##通用写法&#xff0c;忽略就行&#xff0c;与deepseek无关 import pandas as pd from openai.embeddings_utils import get_embedding, cosine_s…

基于 STM32 的病房监控系统

标题:基于 STM32 的病房监控系统 内容:1.摘要 基于 STM32 的病房监控系统摘要&#xff1a;本系统采用 STM32 微控制器作为核心&#xff0c;通过传感器实时监测病房内的环境参数&#xff0c;如温度、湿度、光照等&#xff0c;并将数据上传至云端服务器。医护人员可以通过手机或…

Java分布式幂等性怎么设计?

在高并发的场景的架构中&#xff0c;幂等性是必须得保证的。比如说支付功能&#xff0c;用户发起支付&#xff0c;如果后台没有坐幂等性校验&#xff0c;刚好用户手抖多点了几下&#xff0c;于是后台就有可能多次收到同一个请求&#xff0c;不做幂等性校验很容易就让用户重复支…

Pdf手册阅读(1)--数字签名篇

原文阅读摘要 PDF支持的数字签名&#xff0c; 不仅仅是公私钥签名&#xff0c;还可以是指纹、手写、虹膜等生物识别签名。PDF签名的计算方式&#xff0c;可以基于字节范围进行计算&#xff0c;也可以基于Pdf 对象&#xff08;pdf object&#xff09;进行计算。 PDF文件可能包…

Debezium系列之:时区转换器,时间戳字段转换到指定时区

Debezium系列之:时区转换器,时间戳字段转换到指定时区 示例:基本配置应用TimezoneConverter SMT的效果示例:高级配置配置选项当Debezium发出事件记录时,记录中的时间戳字段的时区值可能会有所不同,这取决于数据源的类型和配置。为了在数据处理管道和应用程序中保持数据一…

Zabbix-监控SSL证书有效期

背景 项目需要&#xff0c;需要监控所有的SSL证书的有效期&#xff0c;因此需要自定义一个监控项 实现 创建自定义脚本 在Zabbix的scripts目录(/etc/zabbix/scripts/)下创建一个新的shell脚本check_ssl.sh&#xff0c;内容如下 #!/bin/bash time$(echo | openssl s_client…

【AI知识点】大模型开源的各种级别和 deepseek 的开源级别

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】【读书与思考】【AI应用】 大模型开源的各种级别 大模型的“开源”程度不同&#xff0c;通常可以分为以下几个主要级别&#xff1a; 1. 权重不开源&#xff08;Closed-source&#xff09; 特点&#xff1a;仅…

java安全中的类加载

java安全中的类加载 提前声明: 本文所涉及的内容仅供参考与教育目的&#xff0c;旨在普及网络安全相关知识。其内容不代表任何机构、组织或个人的权威建议&#xff0c;亦不构成具体的操作指南或法律依据。作者及发布平台对因使用本文信息直接或间接引发的任何风险、损失或法律纠…

探索 API 文档新境界:Swagger 助力生成带权限控制的 API 文档

各位开发者朋友们&#xff01;在咱们的开发工作里&#xff0c;API 文档就像是项目的说明书&#xff0c;清晰准确的文档能让我们的开发效率大幅提升。而当涉及到权限控制时&#xff0c;如何生成既安全又详细的 API 文档就成了一个关键问题。今天&#xff0c;我就和大家好好唠唠如…

只需三步!5分钟本地部署deep seek——MAC环境

MAC本地部署deep seek 第一步:下载Ollama第二步:下载deepseek-r1模型第三步&#xff1a;安装谷歌浏览器插件 第一步:下载Ollama 打开此网址&#xff1a;https://ollama.com/&#xff0c;点击下载即可&#xff0c;如果网络比较慢可使用文末百度网盘链接 注&#xff1a;Ollama是…

神经网络常见激活函数 9-CELU函数

文章目录 CELU函数导函数函数和导函数图像优缺点pytorch中的CELU函数tensorflow 中的CELU函数 CELU 连续可微指数线性单元&#xff1a;CELU&#xff08;Continuously Differentiable Exponential Linear Unit&#xff09;,是一种连续可导的激活函数&#xff0c;结合了 ELU 和 …

w~自动驾驶~合集17

我自己的原文哦~ https://blog.51cto.com/whaosoft/13269720 #FastOcc 推理更快、部署友好Occ算法来啦&#xff01; 在自动驾驶系统当中&#xff0c;感知任务是整个自驾系统中至关重要的组成部分。感知任务的主要目标是使自动驾驶车辆能够理解和感知周围的环境元素&#…

Visual Studio 进行单元测试【入门】

摘要&#xff1a;在软件开发中&#xff0c;单元测试是一种重要的实践&#xff0c;通过验证代码的正确性&#xff0c;帮助开发者提高代码质量。本文将介绍如何在VisualStudio中进行单元测试&#xff0c;包括创建测试项目、编写测试代码、运行测试以及查看结果。 1. 什么是单元测…

解决珠玑妙算游戏问题:C 语言实现

一、引言 珠玑妙算游戏&#xff08;the game of master mind&#xff09;是一个有趣的逻辑推理游戏。在编程领域&#xff0c;我们可以通过编写代码来模拟游戏中计算猜中与伪猜中次数的过程。本文将详细介绍如何使用 C 语言实现这一功能&#xff0c;并对核心代码进行解析。 二、…