【C++】string的模拟实现

【C++】string的模拟实现

文章目录

string的模拟实现

1.1 经典的string类问题

上面已经对string类进行了简单的介绍,大家只要能够正常使用即可。在面试中,面试官总喜欢让 学生自己来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析 构函数。大家看下以下string类的实现是否有问题?

// 为了和标准库区分,此处使用StringclassString{public:/*String() :_str(new char[1]) {*_str = '\0';} *///String(const char* str = "\0") 错误示范//String(const char* str = nullptr) 错误示范String(constchar* str =""){// 构造String类对象时,如果传递nullptr指针,可以认为程序非if(nullptr== str){assert(false);return;} _str =newchar[strlen(str)+1];strcpy(_str, str);}~String(){if(_str){delete[] _str; _str =nullptr;}}private:char* _str;};// 测试voidTestString(){ String s1("hello bit!!!"); String s2(s1);}
在这里插入图片描述

说明:上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认 的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内 存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

1.2 浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致 多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该 资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。

就像一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一块玩,则万事大吉,万一 不想分享就你争我夺,玩具损坏。

可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。父 母给每个孩子都买一份玩具,各自玩各自的就不会有问题了。

在这里插入图片描述

1.3 深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给
出。一般情况都是按照深拷贝方式提供。

在这里插入图片描述

模拟实现

构造函数的模拟实现

//传统写法/*string(const string& s) { _str = new char[s._capacity + 1]; strcpy(_str, s._str); _size = s._size; _capacity = s._capacity; }*///s2(s1) tmp是s2//现代写法string(const string& s){ string tmp(s._str);//默认构造swap(tmp);//把tmp和s2交换}

赋值重载的模拟实现

//s2=s1 赋值//传统写法/*string& operator=(const string& s) { if (this != &s) { delete[] _str; _str = new char[s._capacity + 1]; _size = s._size; _capacity = s._capacity; } return *this; }*///s1=s3//string& operator=(const string& s)//{// if (this != &s)// {// //把s3的内容都给tmp.然后s1与tmp交换// //string tmp(s._str); 调用默认构造// string tmp(s);//调用拷贝构造// swap(tmp);// }// //而且tmp出了作用域自动销毁// return *this;//}//最新版本的赋值 string&operator=(string tmp)//拷贝构造必须用引用,不然会无穷递归 但赋值不用{swap(tmp);return*this;}

析构的模拟实现

~string(){delete[] _str; _str =nullptr; _capacity = _size =0;}

clear的模拟实现

voidclear(){ _str[0]='\0'; _size =0;}

reserve的模拟实现

void string::reserve(size_t n){if(n > _capacity){char* tmp =newchar[n +1];//永远多开一个空间strcpy(tmp, _str);delete[] _str; _str = tmp; _capacity = n;}}

push_back的模拟实现

void string::push_back(char ch){if(_size == _capacity){reserve(_capacity ==0?4: _capacity *2);} _str[_size]= ch;++_size; _str[_size]='\0';}

append的模拟实现

void string::append(constchar* str){ size_t len =strlen(str);if(_size + len > _capacity){reserve(_size + len > _capacity *2? _size + len : _capacity *2);}strcpy(_str + _size, str);//_str+size就是\0的位置 _size += len;}

insert的模拟实现

void string::insert(size_t pos,char ch)//插字符{assert(pos <= _size);if(_size == _capacity){reserve(_capacity ==0?4: _capacity *2);} size_t end = _size+1;while(end > pos){ _str[end]= _str[end-1];//如果end=_size _str[end+1]=_str[size] 当end减到-1时与pos比较会隐式类型转换--end;} _str[pos]= ch;++_size;}void string::insert(size_t pos,constchar* str)//插字符串{assert(pos <= _size);//扩容 size_t len =strlen(str);if(_size + len > _capacity){reserve(_size + len > _capacity *2? _size + len : _capacity *2);} size_t end = _size + len;if(len ==0)return;while(end > pos + len-1)//end=pos+len时也要继续{ _str[end]= _str[end-len];--end;}for(size_t i =0; i < len;++i){ _str[pos+i]= str[i];} _size += len;}

erase的模拟实现

void string::erase(size_t pos, size_t len )//缺省参数在声明的时候给{assert(pos < _size);if(len > _size - pos){ _str[pos]='\0'; _size =pos;}else{for(size_t i = pos + len;i<=_size ; i++){ _str[i - len]= _str[i];} _size -= len;}}

find的模拟实现

size_t string::find(char ch, size_t pos){for(size_t i = pos; i < _size; i++){if(_str[i]== ch)return i;}return npos;} size_t string::find(constchar* str, size_t pos){assert(pos < _size);constchar* ptr =strstr(_str + pos, str);//strstr返回第一个字串位置if(ptr ==nullptr){return npos;}else{return ptr - _str;}}

substr的模拟实现

string string::substr(size_t pos , size_t len ){assert(pos < _size);//len太大就调整一下if(len > _size - pos){ len = _size - pos;} string sub; sub.reserve(len);for(size_t i=0;i<len;++i){ sub+= _str[pos + i];}return sub;}

比较运算符的模拟实现

booloperator<(const string& s1,const string& s2){returnstrcmp(s1.c_str(), s2.c_str())<0;}booloperator==(const string& s1,const string& s2){returnstrcmp(s1.c_str(), s2.c_str())==0;}booloperator>(const string& s1,const string& s2){return!(s1 < s2 || s1 == s2);}booloperator<=(const string& s1,const string& s2){return s1 < s2 || s1 == s2;}booloperator>=(const string& s1,const string& s2){return!(s1 < s2);}booloperator!=(const string& s1,const string& s2){return!(s1 == s2);}

流插入的模拟实现

ostream&operator<<(ostream& out,const string& s){for(auto ch : s){ out << ch;}return out;}

流提取的模拟实现

istream&operator>>(istream& in, string& s){ s.clear();constint N =256;char buff[N];int i =0;char ch;//in >> ch; cin默认提取不到空格跟换行 ch = in.get();while(ch !=' '&& ch !='\n'){ buff[i++]= ch;if(i == N -1){ buff[i]='\0'; s += buff; i =0;} s += ch;//in >> ch; ch = in.get();if(i >0){ buff[i]='\0'; s += buff;}}return in;}

完整代码

string.cpp

#include"string.h"namespace bit {void string::reserve(size_t n){if(n > _capacity){char* tmp =newchar[n +1];//永远多开一个空间strcpy(tmp, _str);delete[] _str; _str = tmp; _capacity = n;}}void string::push_back(char ch){if(_size == _capacity){reserve(_capacity ==0?4: _capacity *2);} _str[_size]= ch;++_size; _str[_size]='\0';} string& string::operator+=(char ch){push_back(ch);return*this;}void string::append(constchar* str){ size_t len =strlen(str);if(_size + len > _capacity){reserve(_size + len > _capacity *2? _size + len : _capacity *2);}strcpy(_str + _size, str);//_str+size就是\0的位置 _size += len;} string& string::operator+=(constchar* str){append(str);return*this;}void string::insert(size_t pos,char ch){assert(pos <= _size);if(_size == _capacity){reserve(_capacity ==0?4: _capacity *2);} size_t end = _size+1;while(end > pos){ _str[end]= _str[end-1];//如果end=_size _str[end+1]=_str[size] 当end减到-1时与pos比较会隐式类型转换--end;} _str[pos]= ch;++_size;}void string::insert(size_t pos,constchar* str){assert(pos <= _size);//扩容 size_t len =strlen(str);if(_size + len > _capacity){reserve(_size + len > _capacity *2? _size + len : _capacity *2);} size_t end = _size + len;if(len ==0)return;while(end > pos + len-1)//end=pos+len时也要继续{ _str[end]= _str[end-len];--end;}for(size_t i =0; i < len;++i){ _str[pos+i]= str[i];} _size += len;}void string::erase(size_t pos, size_t len )//缺省参数在声明的时候给{assert(pos < _size);if(len > _size - pos){ _str[pos]='\0'; _size =pos;}else{for(size_t i = pos + len;i<=_size ; i++){ _str[i - len]= _str[i];} _size -= len;}} size_t string::find(char ch, size_t pos){for(size_t i = pos; i < _size; i++){if(_str[i]== ch)return i;}return npos;} size_t string::find(constchar* str, size_t pos){assert(pos < _size);constchar* ptr =strstr(_str + pos, str);//strstr返回第一个字串位置if(ptr ==nullptr){return npos;}else{return ptr - _str;}} string string::substr(size_t pos , size_t len ){assert(pos < _size);//len太大就调整一下if(len > _size - pos){ len = _size - pos;} string sub; sub.reserve(len);for(size_t i=0;i<len;++i){ sub+= _str[pos + i];}return sub;}voidtest_string1(){ string s1; string s2("hello world"); cout << s1.c_str()<< endl; cout << s2.c_str()<< endl;for(size_t i =0; i < s2.size();++i){ s2[i]+=2;} cout << s2.c_str()<< endl;for(auto e : s2){ cout << e <<" ";} cout << endl; string::iterator it = s2.begin();while(it != s2.end()){ cout <<*it <<" ";++it;}}voidtest_string2(){ string s1("hello wwww"); s1 +='x'; cout << s1.c_str()<< endl; s1.insert(3,"sss"); cout << s1.c_str()<< endl; s1.erase(3,2); cout << s1.c_str()<< endl;}voidtest_string3(){ string s("666.cpp.zip"); size_t pos =s.find('.'); string suffix = s.substr(pos); cout << suffix.c_str()<< endl; string copy(s); cout << copy.c_str()<< endl;}booloperator<(const string& s1,const string& s2){returnstrcmp(s1.c_str(), s2.c_str())<0;}booloperator==(const string& s1,const string& s2){returnstrcmp(s1.c_str(), s2.c_str())==0;}booloperator>(const string& s1,const string& s2){return!(s1 < s2 || s1 == s2);}booloperator<=(const string& s1,const string& s2){return s1 < s2 || s1 == s2;}booloperator>=(const string& s1,const string& s2){return!(s1 < s2);}booloperator!=(const string& s1,const string& s2){return!(s1 == s2);} ostream&operator<<(ostream& out,const string& s){for(auto ch : s){ out << ch;}return out;} istream&operator>>(istream& in, string& s){ s.clear();constint N =256;char buff[N];int i =0;char ch;//in >> ch; cin默认提取不到空格跟换行 ch = in.get();while(ch !=' '&& ch !='\n'){ buff[i++]= ch;if(i == N -1){ buff[i]='\0'; s += buff; i =0;} s += ch;//in >> ch; ch = in.get();if(i >0){ buff[i]='\0'; s += buff;}}return in;}voidtest_string4(){ string s1("hello"); cin >> s1 ; cout << s1<<endl; cout <<"he";}}intmain(){ bit::test_string4();}

string.h

#pragmaonce#include<iostream>#include<assert.h>#include<string.h>usingnamespace std;namespace bit {classstring{public://string()// : _str(new char[1]{'\0'})//不能给nullptr 因为会对空指针解引用// , _size(0)// ,_capacity(0)//{}//短小频繁调用的函数,可以直接放到类里面,默认是inlinetypedefchar* iterator;//迭代器就是对各类型的封装 iterator begin(){return _str;} iterator end(){return _str + _size;}typedefconstchar* const_iterator; const_iterator begin()const{return _str;} const_iterator end()const{return _str + _size;} size_t capacity()const{return _capacity;}voidreserve(size_t n);voidpush_back(char ch);voidappend(constchar* str); string&operator+=(char ch); string&operator+=(constchar* str);voidinsert(size_t pos,char ch);voidinsert(size_t pos,constchar* str);voiderase(size_t pos, size_t len = npos); size_t find(char ch, size_t pos =0); size_t find(constchar* str, size_t pos =0); string substr(size_t pos =0, size_t len = npos);string(constchar* str="")//""就相当于一个\0{ _size =strlen(str); _capacity = _size;//capacity不加1,因为capacity不包含\0 _str =newchar[_capacity +1];//空间多开一个放\0strcpy(_str, str);//会把\0也拷贝过去}//s2(s1) 拷贝构造//传统写法/*string(const string& s) { _str = new char[s._capacity + 1]; strcpy(_str, s._str); _size = s._size; _capacity = s._capacity; }*///s2(s1) tmp是s2//现代写法string(const string& s){ string tmp(s._str);//默认构造swap(tmp);//把tmp和s2交换}//s2=s1 赋值//传统写法/*string& operator=(const string& s) { if (this != &s) { delete[] _str; _str = new char[s._capacity + 1]; _size = s._size; _capacity = s._capacity; } return *this; }*///s1=s3//string& operator=(const string& s)//{// if (this != &s)// {// //把s3的内容都给tmp.然后s1与tmp交换// //string tmp(s._str); 调用默认构造// string tmp(s);//调用拷贝构造// swap(tmp);// }// //而且tmp出了作用域自动销毁// return *this;//}//最新版本的赋值 string&operator=(string tmp)//拷贝构造必须用引用,不然会无穷递归 但赋值不用{swap(tmp);return*this;}voidswap(string& s){ std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity);}~string(){delete[] _str; _str =nullptr; _capacity = _size =0;}voidclear(){ _str[0]='\0'; _size =0;}constchar*c_str()const{return _str;} size_t size()const{return _size;}char&operator[](size_t pos){assert(pos < _size);return _str[pos];}constchar&operator[](size_t pos)const{assert(pos < _size);return _str[pos];}private:char* _str=nullptr; size_t _size=0; size_t _capacity=0;//下列这也算定义staticconst size_t npos=-1;//静态成员类外初始化,但是这里可以也直接给,static const才可以在这里直接初始化,而且只有整型可以这么玩};//const size_t npos = -1;}

(tmp);

 return *this; } void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } ~string() { delete[] _str; _str = nullptr; _capacity = _size = 0; } void clear() { _str[0] = '\0'; _size = 0; } const char* c_str() const { return _str; } size_t size() const { return _size; } char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; } private: char* _str=nullptr; size_t _size=0; size_t _capacity=0; //下列这也算定义 static const size_t npos=-1;//静态成员类外初始化,但是这里可以也直接给,static const才可以在这里直接初始化,而且只有整型可以这么玩 }; //const size_t npos = -1; 

}

Read more

字节Seedance2.0:2026年AI视频生成技术突破,从原理到实操全解析

字节Seedance2.0:2026年AI视频生成技术突破,从原理到实操全解析

一、背景引入:2026年AI视频生成的痛点与Seedance2.0的破局意义 2026年,AI产业已从“参数比拼”进入“价值落地”的关键阶段,AI视频生成作为多模态技术落地的核心场景,成为开发者与企业关注的焦点。但当前市场主流工具仍存在三大核心痛点,严重制约落地效率: * 音画不同步:传统模型需后期拼接音频与视频,易出现口型错位、脚步声与动作脱节等问题,适配成本高; * 角色一致性差:多镜头叙事中,人物五官、服装细节易崩坏,无法满足连贯叙事需求; * 实操门槛高:要么需高性能本地硬件部署,要么依赖付费订阅,且参数调试复杂,小白开发者难以快速上手。 在此背景下,字节跳动Seed团队于2026年2月正式发布Seedance2.0,定位“电影级全流程AI视频生成引擎”,凭借三大核心技术突破,精准解决上述痛点[5]。 二、核心技术原理:Seedance2.0的三大突破性架构 Seedance2.0基于字节跳动自研Seed大模型基座优化而来,延续视频技术积累的同时,针对AI视频生成的核心痛点,重构了三大核心技术架构,区别于上一代及传统视频模型[2][5]。 2.

By Ne0inhk
2026 AI十大趋势:木头姐《Big Ideas 2026》深度解读,解锁大加速时代的技术红利

2026 AI十大趋势:木头姐《Big Ideas 2026》深度解读,解锁大加速时代的技术红利

木头姐《Big Ideas 2026》报告指出,AI已成为撬动全球经济“大加速”的核心引擎,不再孤军奋战。本文结合报告核心数据与观点,以幽默接地气的语气,拆解2026年AI十大核心趋势,助力普通人轻松读懂技术红利。 引言 全球科技投资圈“顶流”木头姐(凯茜·伍德),带着她的十周年力作《Big Ideas 2026》如约而至!作为科技圈的“预言家手册”,这份报告每年都能精准预判行业走向,今年更是以“The Great Acceleration”(大加速)为核心,抛出震撼论断:AI早已告别“闭门造车”,成为五大创新平台的“发动机”,正引爆全球经济的变革狂欢。不同于往年聚焦单一技术,今年木头姐重点凸显AI的“全能辅助”角色——自身迭代升级的同时,还在疯狂“带飞”其他技术。接下来,我们就用最轻松的语气,拆解报告里最劲爆的AI十大趋势,

By Ne0inhk
【已开源】【嵌入式 Linux 音视频+ AI 实战项目】瑞芯微 Rockchip 系列 RK3588-基于深度学习的人脸门禁+ IPC 智能安防监控系统

【已开源】【嵌入式 Linux 音视频+ AI 实战项目】瑞芯微 Rockchip 系列 RK3588-基于深度学习的人脸门禁+ IPC 智能安防监控系统

前言 本文主要介绍我最近开发的一个个人实战项目,“基于深度学习的人脸门禁+ IPC 智能安防监控系统”,全程满帧流畅运行。这个项目我目前全网搜了一圈,还没发现有相关类型的开源项目。这个项目只要稍微改进下,就可以变成市面上目前流行的三款产品,人脸识别门禁系统、IPC 安防和 NVR。在最下面会有视频演示。 本项目适用于瑞芯微 Rockchip 系列的板端,开源链接在文章最下面。 功能 人脸门禁系统 * 人靠近自动亮屏,人走自动息屏 * 支持人脸识别 * 支持录入人脸,并进行人脸配对(极速配对 < 0.2S) IPC 智能安防监控系统 * 支持通过 onvif 实时查看摄像头画面 * 支持实时目标检测(支持高达80种物体检测) * 支持录像 * 支持检测到人时自动录像 * 支持检测到人时自动报警 用到的硬件 * 野火鲁班猫4 RK3588S2 * IMX415 800W 4k 摄像头 * RTL8822CE Wifi+BT

By Ne0inhk
猫头虎AI分享|可把GitHub代码库变成实时文档中心的一款实用型MCP工具:GitMCP,让AI随时访问最新文档代码,消除代码幻觉

猫头虎AI分享|可把GitHub代码库变成实时文档中心的一款实用型MCP工具:GitMCP,让AI随时访问最新文档代码,消除代码幻觉

猫头虎AI分享|可把GitHub代码库变成实时文档中心的一款实用型MCP工具:GitMCP,让AI随时访问最新文档代码,消除代码幻觉 背景 随着人工智能(AI)在编程领域的广泛应用,近期GitHub CEO辞职,GitHub独立时代结束,GitMCP AI助理的智能能力可以提高开发者的工作效率。然而,随着代码量的增加和技术栈的不断发展,AI助理在访问和理解不同项目的代码时,常常会发生“代码幻觉”现象,即 AI 给出的答案可能不准确或者与当前项目的实际实现不符。这种现象尤其在没有实时访问代码库的情况下更加严重。 为了解决这个问题,GitMCP应运而生,它是一个基于Model Context Protocol (MCP) 的开源工具,能够帮助AI助手实时获取GitHub上的最新代码和文档,确保AI助手能够精确、可靠地回答问题,避免代码幻觉的发生。 文章目录 * 猫头虎AI分享|**可把GitHub代码库变成实时文档中心的一款实用型MCP工具:GitMCP,让AI随时访问最新文档代码,消除代码幻觉** * 背景 * GitMCP概述 * GitMCP的

By Ne0inhk