C++:string容器(下篇)

1.string浅拷贝的问题

// 为了和标准库区分,此处使用String
class String
{
public :/*String():_str(new char[1]){*_str = '\0';}*///String(const char* str = "\0") // 错误示范//String(const char* str = nullptr) // 错误示范String(const char* str = ""){if (nullptr == str){assert(false);return;} _str = new char[strlen(str) + 1];strcpy(_str, str);   }~String(){if (_str){delete[] _str;_str = nullptr;}}
private:char* _str;
};int main()
{String s1("hello world!");String s2(s1);    // 这里会析构两次,导致程序崩溃return 0;
}

说明:

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

浅拷贝:

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

        可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。

2.深拷贝

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

2.1 传统写法的String类

class String
{
public :String(const char* str = ""){if (nullptr == str){assert(false);return;} _str = new char[strlen(str) + 1];strcpy(_str, str);} String(const String& s): _str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);} String& operator=(const String& s){if (this != &s){char* pStr = new char[strlen(s._str) + 1];strcpy(pStr, s._str);delete[] _str;_str = pStr;} return* this;} ~String(){if (_str){delete[] _str;_str = nullptr;}}private:char* _str;
};

2.1 现代写法的String类

class String
{
public :String(const char* str = ""){// 构造String类对象时,如果传递nullptr指针,可以认为程序非if (nullptr == str){assert(false);return;} _str = new char[strlen(str) + 1];strcpy(_str, str);} String(const String& s): _str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);} // 现代版本String & operator=(String s){std::swap(_str, s._str);return *this;}传统版本//String& operator=(const String& s)//{//	if (this != &s)//	{//		char* pStr = new char[strlen(s._str) + 1];//		strcpy(pStr, s._str);//		delete[] _str;//		_str = pStr;//	} //	return* this;//} ~String(){if (_str){delete[] _str;_str = nullptr;}}private:char* _str;
};

3.string类的模拟实现

头文件 string.h:

namespace room
{class string{public:// 迭代器typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}/*string():_str(new char[1]{'\0'}),_size(0),_capacity(0){}*/void swap(string& s);string(size_t n, char ch);string(const char* str = "");// s2(s1)string(const string& s);// s1 = s2// s1 = s1//string& operator=(const string& s);// s1 = s2string& operator=(string s);~string();void clear(){_str[0] = '\0';_size = 0;}const char* c_str() const{return _str;}void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, size_t n, char ch);void insert(size_t pos, const char* ch);void erase(size_t pos = 0, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);size_t size() const{return _size;}size_t capacity() 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];}string substr(size_t pos, size_t len = npos);bool operator==(const string& s) const;bool operator!=(const string& s) const;bool operator<(const string& s) const;bool operator<=(const string& s) const;bool operator>(const string& s) const;bool operator>=(const string& s) const;private:// 声明char* _str = nullptr;size_t _size = 0;size_t _capacity = 0;const static size_t npos;};ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);istream& getline(istream& in, string& s, char delim);
}

源文件string.cpp:

// 链接时会合并
namespace room 
{const size_t string::npos = -1;string::string(size_t n, char ch):_str(new char[n + 1]),_size(n),_capacity(n){for (size_t i = 0; i < n; ++i){_str[i] = ch;}_str[_size] = '\0';}string::string(const char* str):_size(strlen(str)){_capacity = _size;_str = new char[_size + 1];strcpy(_str, str);}传统写法s2(s1)//string::string(const string& s)//{//	_str = new char[s._capacity + 1];//	strcpy(_str, s._str);//	_size = s._size;//	_capacity = s._capacity;//}void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}// 现代写法// s2(s1)string::string(const string& s){string tmp(s._str);swap(tmp);}// s1 = s2// s1 = s1/*string& string::operator=(const string& s){if (this != &s){delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}*/// s1 = s2string& string::operator=(string s){swap(s);return *this;}string::~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}void string::reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::push_back(char ch){if (_size + 1 > _capacity){// 扩容reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';	// 末尾得加上一个\0}void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){// 扩容size_t newCapacity = 2 * _capacity;if(_size + len > 2 * _capacity){newCapacity = _size + len;}reserve(newCapacity);}strcpy(_str + _size, str);_size += len;}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}void string::insert(size_t pos, size_t n, char ch){assert(pos <= _size);assert(n > 0);if (_size + n > _capacity){// 扩容size_t newCapacity = 2 * _capacity;if (_size + n > 2 * _capacity){newCapacity = _size + n;}reserve(newCapacity);}// 挪动数据// 这样挪动数据,头插的时候会越界/*size_t end = _size;while (end >= pos){_str[end + n] = _str[end];--end;}*/size_t end = _size + n;while (end > pos + n - 1){_str[end] = _str[end - n];--end;}for (size_t i = 0; i < n; ++i){_str[pos + i] = ch;}_size += n;/*string tmp(n, ch);insert(pos, tmp.c_str());*/}void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t n = strlen(str);if (_size + n > _capacity){// 扩容size_t newCapacity = 2 * _capacity;if (_size + n > 2 * _capacity){newCapacity = _size + n;}reserve(newCapacity);}size_t end = _size + n;while (end > pos + n - 1){_str[end] = _str[end - n];--end;}for (size_t i = 0; i < n; ++i){_str[pos + i] = str[i];}}void string::erase(size_t pos, size_t len){if (len >= _size - pos){// 删完数据_str[pos] = '\0';_size = pos;}else{size_t end = pos + len;while (end <= _size){_str[end - len] = _str[end];++end;}_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(const char* str, size_t pos){const char* p = strstr(_str + pos, str);if (p == nullptr){return npos;}else{return p - _str;}}string string::substr(size_t pos, size_t len){size_t leftlen = _size - pos;// 给的长度大于剩余的长度时,len等于剩余长度if (len > leftlen)len = leftlen;string tmp;tmp.reserve(len);for (size_t i = 0; i < len; ++i){tmp += _str[pos + i];}return tmp;}bool string::operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool string::operator!=(const string& s) const{return !(*this == s);}bool string::operator<(const string& s) const{return strcmp(_str, s._str) < 0;}bool string::operator<=(const string& s) const{return *this < s || *this == s;}bool string::operator>(const string& s) const{return !(*this <= s);}bool string::operator>=(const string& s) const{return !(*this < s);}ostream& operator<<(ostream& out, const string& s){for (auto ch : s)out << ch;return out;}istream& operator>>(istream& in, string& s){s.clear();// 输入短串,不会浪费空间// 输入长串,避免不断扩容const size_t N = 1024;char buff[N];int i = 0;//cin >> i;	// 这样是不行的char ch = in.get();	// 用get()才能收到空格和换行// 短串就放入buffwhile (ch != ' ' && ch != '\n')	// 遇到\n就结束{buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){// 长串才扩容,减小扩容带来的性能消耗buff[i] = '\0';s += buff;}return in;}istream& getline(istream& in, string& s, char delim){s.clear();// 输入短串,不会浪费空间// 输入长串,避免不断扩容const size_t N = 1024;char buff[N];int i = 0;//cin >> i;	// 这样是不行的char ch = in.get();	// 用get()才能收到空格和换行// 短串就放入buffwhile (ch != delim)	// 遇到指定字符delim就结束{buff[i++] = ch;if (i == N - 1){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i > 0){// 长串才扩容,减小扩容带来的性能消耗buff[i] = '\0';s += buff;}return in;}
}

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

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

相关文章

使用 vxe-table 导出 excel,支持带数值、货币、图片等带格式导出

使用 vxe-table 导出 excel&#xff0c;支持带数值、货币、图片等带格式导出&#xff0c;通过官方自动的导出插件 plugin-export-xlsx 实现导出功能 查看官网&#xff1a;https://vxetable.cn gitbub&#xff1a;https://github.com/x-extends/vxe-table gitee&#xff1a;htt…

JavaScript数据类型和内存空间

一、JavaScript 数据类型 基本数据类型&#xff1a;字符串&#xff08;String&#xff09;、数字(Number)、布尔(Boolean)、空&#xff08;Null&#xff09;、未定义&#xff08;Undefined&#xff09;、Symbol 引用数据类型&#xff1a;对象(Object)、数组(Array)、函数(Fun…

DNS Beaconing

“DNS Beaconing” 是一种隐蔽的网络通信技术&#xff0c;通常与恶意软件&#xff08;如木马、僵尸网络&#xff09;相关。攻击者通过定期发送 DNS请求 到受控的域名服务器&#xff08;C&C服务器&#xff09;&#xff0c;实现与恶意软件的隐蔽通信、数据传输或指令下发。由…

python中采用opencv作常规的图片处理的方法~~~

在python中&#xff0c;我们经常会需要对图片做灰度/二值化/模糊等处理&#xff0c;这时候opencv就是我们的好帮手了&#xff0c;下面我来介绍一下相关用法: 首先&#xff0c;需要安装opencv-python库: 然后&#xff0c;在你的代码中引用: import cv2 最后就是代码了&#x…

CmBacktrace的学习跟移植思路

学习移植CmBacktrace需要从理解其核心功能、适用场景及移植步骤入手&#xff0c;结合理论学习和实践操作。以下是具体的学习思路与移植思路&#xff1a; 一、学习思路 理解CmBacktrace的核心功能 CmBacktrace是针对ARM Cortex-M系列MCU的错误追踪库&#xff0c;支持自动诊断Har…

支付宝当面付java,php,sdk下载

SDK & Demo 获取 - 支付宝文档中心 开放平台服务端 SDK 为了帮助开发者调用开放接口&#xff0c;支付宝提供了开放平台服务端 SDK&#xff0c;包含 Java、PHP、NodeJS、Python 和 .NET 等语言版本&#xff0c;DEMO 中封装了签名 & 验签、HTTP 接口请求等基础功能。 详…

Cocos Creator Shader入门实战(三):CCEffect参数配置讲解

引擎版本&#xff1a;3.8.5 您好&#xff0c;我是鹤九日&#xff01; 回顾 稍微回顾下前面两篇博客讲解的内容&#xff1a; 一、Cocos渲染效果的实现需要Material材质和Effect资源的互相配合。 二、Effect资源负责Shader片段的编写和属性配置&#xff0c;Material材质负责对E…

AI日报 - 2025年3月10日

AI日报 - 2025年3月10日 &#x1f31f; 今日概览&#xff08;60秒速览&#xff09; ▎&#x1f916; AGI突破 | Anthropic CEO预测强AI最早2026年到来 &#x1f52c; SAGE框架提升问答质量61.25%&#xff0c;Reflexion框架将GPT-4成功率提至91% ▎&#x1f4bc; 商业动向 | xA…

【SegRNN 源码理解】【今天不水文系列】编码器部分理解

我来小小的理解一下&#xff1a; 首先&#xff0c;16 batchsize&#xff0c;60sequendcelength&#xff0c;7 个特征的通俗解释 16 个独立的样本&#xff0c;每个样本有 60 个连续的时间步及对应的标签值&#xff0c;每个时间步有 60 个特征 所以就是因为样本是随机从训练集…

加速科技Flex10K-L测试机:以硬核创新重塑显示驱动芯片测试新标杆!

在2024年召开的世界显示产业创新发展大会上&#xff0c;加速科技自主研发的高密度显示驱动芯片测试设备Flex10K-L凭借其突破性技术创新&#xff0c;成功入选"十大创新技术&#xff08;产品&#xff09;"。作为国内显示驱动芯片测试领域的标杆性设备&#xff0c;Flex1…

Docker 部署 Vaultwarden

一、前言 1. 官网 1.1 Vaultwarden https://github.com/dani-garcia/vaultwarden https://github.com/wcjxixi/Vaultwarden-Wiki-Chn https://hub.docker.com/r/vaultwarden/server https://rs.ppgg.in/ # Vaultwarden Wiki 中文版 https://geekdaxue.co/read/Vaultward…

如何下载和使用Git:初学者指南

&#x1f31f; 如何下载和使用Git&#xff1a;初学者指南 在当今的软件开发中&#xff0c;Git已经成为不可或缺的版本控制系统。无论你是独立开发者还是团队成员&#xff0c;掌握Git的基本操作都能帮助你更高效地管理代码。今天&#xff0c;我将详细介绍如何下载和使用Git&…

doris: SQL Server

Doris JDBC Catalog 支持通过标准 JDBC 接口连接 SQL Server 数据库。本文档介绍如何配置 SQL Server 数据库连接。 使用须知​ 要连接到 SQL Server 数据库&#xff0c;您需要 SQL Server 2012 或更高版本&#xff0c;或 Azure SQL 数据库。 SQL Server 数据库的 JDBC 驱动…

Leetcode 刷题记录 05 —— 普通数组

本系列为笔者的 Leetcode 刷题记录&#xff0c;顺序为 Hot 100 题官方顺序&#xff0c;根据标签命名&#xff0c;记录笔者总结的做题思路&#xff0c;附部分代码解释和疑问解答。 目录 01 最大子数组和 方法一&#xff1a;动态规划&#xff08;卡达尼算法&#xff09; 方法…

《DataWorks 深度洞察:量子机器学习重塑深度学习架构,决胜复杂数据战场》

在数字化浪潮汹涌澎湃的当下&#xff0c;大数据已然成为推动各行业发展的核心动力。身处这一时代洪流&#xff0c;企业对数据的处理与分析能力&#xff0c;直接关乎其竞争力的高低。阿里巴巴的DataWorks作为大数据领域的扛鼎之作&#xff0c;凭借强大的数据处理与分析能力&…

wordpress自定the_category的输出结构

通过WordPress的过滤器the_category来自定义输出内容。方法很简单&#xff0c;但是很实用。以下是一个示例代码&#xff1a; function custom_the_category($thelist, $separator , $parents ) {// 获取当前文章的所有分类$categories get_the_category();if (empty($categ…

2025牛客寒假算法基础集训营6

A.复制鸡 思路&#xff1a;比较简单&#xff0c;略。 void solve() {int n, m, k;cin >> n;int last -1, ans 0;for (int i 0; i<n; i){int x;cin >> x;if (x ! last){ans;}last x;}cout << ans << endl; } B.好伙计猜拳 思路&#xff1a;这…

【C#】详解C#中的内存管理机制

文章目录 前言一、C#内存管理的基本机制&#xff08;1&#xff09;托管堆&#xff08;Managed Heap&#xff09;&#xff08;2&#xff09;垃圾回收&#xff08;Garbage Collection&#xff09;&#xff08;3&#xff09;栈内存 二、 开发者需要主动管理的场景&#xff08;1&am…

ROS云课基础题库-01C++案例-甜甜圈

效率是核心&#xff0c;但效率高的教程会忽略掉非常多的细节。 解决问题的思路和细节对于一个问题的有效求解至关重要。 资料 云课五分钟-02第一个代码复现-终端甜甜圈C-CSDN博客 从云课五分钟到五秒钟焦虑的甜甜圈向前冲-CSDN博客 说明 复现重要性没有那么大&#xff0c;…

C/S架构与B/S架构

一、定义与核心区别 C/S架构&#xff08;Client/Server&#xff0c;客户端/服务器&#xff09; 客户端需安装专用软件&#xff08;如QQ、企业ERP系统&#xff09;&#xff0c;直接与服务器通信。服务器端通常包括数据库和业务逻辑处理1。特点&#xff1a;客户端承担部分计算任务…