日常知识点之面试后反思裸写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:结合结果分析:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【AI论文】10亿参数大语言模型能超越405亿参数大语言模型吗?重新思考测试时计算最优缩放

摘要&#xff1a;测试时缩放&#xff08;Test-Time Scaling&#xff0c;TTS&#xff09;是一种通过在推理阶段使用额外计算来提高大语言模型&#xff08;LLMs&#xff09;性能的重要方法。然而&#xff0c;目前的研究并未系统地分析策略模型、过程奖励模型&#xff08;Process …

【漫话机器学习系列】088.常见的输出层激活函数(Common Output Layer Activation Functions)

在神经网络中&#xff0c;输出层&#xff08;Output Layer&#xff09; 的激活函数&#xff08;Activation Function&#xff09;直接决定了模型的输出形式&#xff0c;并影响损失函数的选择及训练效果。不同的任务类型&#xff08;如分类或回归&#xff09;需要使用不同的激活…

在实体机和wsl2中安装docker、使用GPU

正常使用docker和gpu&#xff0c;直接命令行安装dcoker和&#xff0c;nvidia-container-toolkit。区别在于&#xff0c;后者在于安装驱动已经cuda加速时存在系统上的差异。 1、安装gpu驱动 在实体机中&#xff0c;安装cuda加速包&#xff0c;我们直接安装 driver 和 cuda 即可…

麒麟v10 server版安装ollama跑Deepseek

麒麟v10 server版安装ollama跑Deepseek 1. 环境 2. 安装docker yum install docker 发现源只有18.x版本&#xff0c;启动ollama&#xff0c;发现调用CPU&#xff0c;没调用GPU docker19.x以上才 会调用GPU, 可以添加centos8的原&#xff0c;安装docker-ce3.启动ollama&#…

LabVIEW用户界面(UI)和用户体验(UX)设计

作为一名 LabVIEW 开发者&#xff0c;满足功能需求、保障使用便捷与灵活只是基础要求。在如今这个用户体验至上的时代&#xff0c;为 LabVIEW 应用程序设计直观且具有美学感的界面&#xff0c;同样是不容忽视的关键任务。一个优秀的界面设计&#xff0c;不仅能提升用户对程序的…

如何使用Java语言在Idea和Android中分别建立服务端和客户端实现局域网聊天

手把手教你用Java语言在Idea和Android中分别建立服务端和客户端实现局域网聊天 目录 文章目录 手把手教你用**Java**语言在**Idea**和**Android**中分别建立**服务端**和**客户端**实现局域网聊天**目录**[toc]**基本实现****问题分析****服务端**Idea:结构预览Server类代码解…

【实战篇】DeepSeek + ElevenLabs:让人工智能“开口说话”,打造你的专属语音助手!

最近,AI语音合成技术真是火得不行,各种“开口脆”的AI声音层出不穷,听得我直呼“这也太像真人了吧!” 作为一个科技爱好者,我当然不能错过这股潮流,这不,最近就沉迷于用 DeepSeek 和 ElevenLabs 这两款神器,捣鼓各种人声音频,简直停不下来! 先来科普一下这两位“主角…

vscode/cursor+godot C#中使用socketIO

在 Visual Studio Code(VS Code)中安装 NuGet 包&#xff08;例如SocketIOClient&#xff09;&#xff0c;你可以通过以下几种方法&#xff1a; 方法 1&#xff1a;使用dotnet cli 打开终端&#xff1a;在 VS Code 中按下Ctrl 或者通过菜单View -> Terminal打开终端。 导…

ETL的使用(sqoop):数据导入,导出

ETL ETL: 是数据抽取&#xff08;Extract&#xff09;、数据转换&#xff08;Transform&#xff09;和数据加载&#xff08;Load&#xff09;的整个过程 常用的ETL工具 sqoop 1.Apache Sqoop 是 Apache 软件基金会旗下的一个开源项目&#xff0c;旨在帮助用户高效地在 Hado…

安卓手游内存call综合工具/内部call/安卓注入call/数据分析(类人猿学院)

进程分析注入综合工具总界面 模块分析函数分析遍历 函数分析 so汇编分析 汇编call植入器&#xff0c;支持模拟器x86 x64 和手机arm64指令全平台 防ce搜索数据功能 全国首套发布&#xff0c;阿凡老师学院最好的安卓内存逆向老师&#xff0c;几乎行业最强的&#xff0c;有兴趣可以…

Transformer 详解:了解 GPT、BERT 和 T5 背后的模型

目录 什么是 Transformer? Transformer如何工作? Transformer 为何有用? 常见问题解答:机器学习中的 Transformer 在技​​术领域,突破通常来自于修复损坏的东西。制造第一架飞机的人研究过鸟类。莱特兄弟观察了秃鹫如何在气流中保持平衡,意识到稳定性比动力更重要。…

在C++的DLL文件中定义的结构体,在DLL外可以使用吗,如何使用?

在C的DLL文件中定义的结构体&#xff0c;在DLL外可以使用&#xff0c;但需要正确处理类型匹配和内存管理。‌ 在DLL外使用DLL中定义的结构体的方法&#xff1a; 一、 ‌使用extern "C"声明‌&#xff1a; 在DLL的导出声明中使用extern "C"可以确保函数和…

PDF另存为图片的一个方法

说明 有时需要把PDF的每一页另存为图片。用Devexpress可以很方便的完成这个功能。 窗体上放置一个PdfViewer。 然后循环每一页 for (int i 1; i < pdfViewer1.PageCount; i) 调用 chg_pdf_to_bmp函数获得图片并保存 chg_pdf_to_bmp中调用了PdfViewer的CreateBitmap函数…

中间件-安装Minio-集成使用(ubantu-docker)

目录 1、安装docer 2、运行以下命令拉取MinIO的Docker镜像 3、检查当前所有Docker下载的镜像 4、创建目录 5、创建Minio容器并运行 6、SDK操作 FileUploader.java 1、安装docer 参考这篇&#xff1a;Linux安装Docker 2、运行以下命令拉取MinIO的Docker镜像 docker pull…

ffmpeg学习:ubuntu下编译Android版ffmpeg-kit

文章目录 前言一. 配置环境1.1 虚拟机版本1.2 安装Android环境1.2.1 Android SDK安装1.2.2 Android NDK安装 1.3 编译前的准备工作1.3.1 libtasn1-1安装1.3.2 meson安装1.3.3 harfbuzz下载 二. 编译ffmpeg-kit三. 总结 前言 ffmpeg-kit是一款跨多个平台的&#xff0c;用于在应…

【全球人口数据集】全球人口密度数据集GPWv4

目录 数据概述数据处理方法数据下载参考GPWv4: Population Density, Revision 11 是由 NASA Socioeconomic Data and Applications Center (SEDAC) 提供的全球人口密度数据集,旨在支持社会经济和环境研究。 数据概述 Gridded Population of the World, Version 4 (GPWv4): Po…

PyTorch 中 `torch.cuda.amp` 相关警告的解决方法

在最近的写代码过程中&#xff0c;遇到了两个与 PyTorch 的混合精度训练相关的警告信息。这里随手记录一下。 警告内容 警告 1: torch.cuda.amp.autocast FutureWarning: torch.cuda.amp.autocast(args...) is deprecated. Please use torch.amp.autocast(cuda, args...) i…

NLP面试之-激活函数

一、动机篇 1.1 为什么要有激活函数&#xff1f; 数据角度&#xff1a;由于数据是线性不可分的&#xff0c;如果采用线性化&#xff0c;那么需要复杂的线性组合去逼近问题&#xff0c;因此需要非线性变换对数据分布进行重新映射;线性模型的表达力问题&#xff1a;由于线性模型…

四、自然语言处理_08Transformer翻译任务案例

0、前言 在Seq2Seq模型的学习过程中&#xff0c;做过一个文本翻译任务案例&#xff0c;多轮训练后&#xff0c;效果还算能看 Transformer作为NLP领域的扛把子&#xff0c;对于此类任务的处理会更为强大&#xff0c;下面将以基于Transformer模型来重新处理此任务&#xff0c;看…

关于conda换镜像源,pip换源

目录 1. 查看当前下载源2. 添加镜像源2.1清华大学开源软件镜像站2.2上海交通大学开源镜像站2.3中国科学技术大学 3.删除镜像源4.删除所有镜像源&#xff0c;恢复默认5.什么是conda-forge6.pip换源 1. 查看当前下载源 conda config --show channels 如果发现多个 可以只保留1个…