《回溯 C++98:string 核心机制拆解 —— 从拷贝策略到高效 swap》

《回溯 C++98:string 核心机制拆解 —— 从拷贝策略到高效 swap》

🔥草莓熊Lotso:个人主页

❄️个人专栏:《C++知识分享》《Linux 入门到实践:零基础也能懂》

生活是默默的坚持,毅力是永久的享受。


🎬博主简介:


目录

前言:

一. 字符串的拷贝机制:从浅拷贝到写时拷贝

1.1 浅拷贝:隐藏的 “双重释放” 陷阱

1.2 深拷贝:独立内存的安全保障

1.2.1 传统版写法的string类

1.2.2 现代版写法的string类

1.3 写时拷贝(了解就可以):读写分离的优化策略

二、C++98/03 中的三种 swap 实现

2.1 成员函数 swap:O (1) 级别的高效交换

2.2 全局 swap(默认实现):低效的拷贝交换

2.3 全局 swap(优化版本):复用成员 swap 的高效实现

三、总结:拷贝与交换的设计巧思

结尾:


前言:

在 C++11 引入移动语义之前,std::string的实现依赖于深拷贝、写时拷贝(Copy-On-Write)等经典内存管理策略,而swap 操作则是提升性能的关键优化点。本文聚焦 C++11 之前string的三大swap实现与拷贝机制,带你理解早期字符串类设计的核心智慧。

一. 字符串的拷贝机制:从浅拷贝到写时拷贝

字符串的拷贝是内存管理的核心场景,错误的拷贝实现会导致内存泄漏或程序崩溃,而优化的拷贝策略则能显著提升性能。

1.1 浅拷贝:隐藏的 “双重释放” 陷阱

浅拷贝是最直观但危险的拷贝方式,其本质是仅复制指针地址而非实际数据,导致多个对象共享同一块内存。

问题展现:

namespace Lotso { class string { private: char* _str; size_t _size; public: // 构造函数:分配内存并初始化 string(const char*) : _size(strlen(str)) { _str = new char[_size + 1]; strcpy(_str, str); } // 未实现深拷贝,使用编译器默认的浅拷贝 ~string() { delete[] _str; } // 析构时释放内存 }; // 崩溃 int main() { string s1("hello"); string s2 = s1; // 浅拷贝:s1._str 与 s2._str 指向同一块内存 return 0; // 析构时:s2 先释放内存,s1 再释放已被释放的内存→两个释放同一块内存程序崩溃 } }; 

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

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

1.2 深拷贝:独立内存的安全保障

深拷贝通过为每个对象分配独立内存并复制数据,彻底避免资源共享,是最安全的拷贝方式。

1.2.1 传统版写法的string类

class String { public: String(const char*) { // 构造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=(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; };

优势:每个对象拥有独立内存,析构时不会冲突;

缺点:每次拷贝都需分配内存和复制数据,效率较低(O (n) 时间复杂度)

1.2.2 现代版写法的string类

class String { public: String(const char*) { if (nullptr == str) { assert(false); return; } _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& s) : _str(nullptr) { String strTmp(s._str); swap(_str, strTmp._str); } // 对比下和上面的赋值那个实现比较好? String& operator=(String s) { swap(_str, s._str); return *this; } /* String& operator=(const String& s) { if(this != &s) { String strTmp(s); swap(_str, strTmp._str); } return *this; } */ ~String() { if (_str) { delete[] _str; _str = nullptr; } } private: char* _str; };

核心逻辑:借助临时对象的深拷贝,通过swap将临时对象的资源 “转移” 到当前对象,临时对象析构时会自动释放原对象的旧内存,既避免数据丢失,又简化代码。

1.3 写时拷贝(了解就可以):读写分离的优化策略

  • 写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
  • 引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。
推荐两篇大佬的文章:

C++ STL string的Copy-On-Write技术 | 酷 壳 - CoolShell

https://coolshell.cn/articles/1443.html扩展阅读:

C++面试中string类的一种正确写法 | 酷 壳 - CoolShell

STL 的string类怎么啦?_string拥有庞大字符串 c++-ZEEKLOG博客

二、C++98/03 中的三种 swap 实现

  • swap用于交换两个字符串的内容,不同实现的效率差异显著,核心是 “是否避免数据拷贝”。

2.1 成员函数 swap:O (1) 级别的高效交换

string类的成员swap直接交换底层资源(指针、大小、引用计数等),不涉及数据拷贝,是效率最高的实现。

代码实现:

class String { public: void swap(String& s) { // 交换核心成员,无数据拷贝 std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } private: char* _str; size_t _size; size_t _capacity; };

优势

  • 效率极致:无论字符串长度如何,均为 O (1) 时间复杂度;
  • 无内存风险:交换后资源所有权转移,析构时各自释放原有资源。

2.2 全局 swap(默认实现):低效的拷贝交换

C++ 标准库提供的全局std::swap模板,默认逻辑是 “拷贝 - 覆盖 - 析构”,对字符串而言效率极低。

代码实现:

template <class T> void swap(T& a, T& b) { T c(a);// 深拷贝 a 到临时对象(O(n) a = b; //深拷贝 b 到 a(O(n)) b = c;// 深拷贝临时对象到 b(O(n)) }

问题:对长字符串而言,三次深拷贝会导致 O (n) 时间复杂度,性能极差。

2.3 全局 swap(优化版本):复用成员 swap 的高效实现

为解决默认swap的低效问题,标准库会为std::string提供模板特化,直接调用成员swap,将效率提升至 O (1)。

代码实现:

inline void swap(string& a, string& b) { //还是调的库里的 a.swap(b); }

优势:兼顾通用性与效率,在模板函数(如排序算法)中使用试探大std::swap时,仍能享受高效交换。

三、总结:拷贝与交换的设计巧思

在 C++11 之前,string的设计围绕 “内存效率” 与 “安全性” 展开:

拷贝机制的选择

  • 深拷贝:安全但低效,适合写操作频繁的场景;
  • 写时拷贝:读多写少场景下的优化,但存在线程安全与迭代器失效问题,现代编译器已逐渐弃用。

swap 实现的最优实践

  • 优先使用成员swap:直接交换资源,效率最高;
  • 全局swap优化:标准库已帮我们优化,无需手动实现,但需知道其底层依赖成员swap的本质。

结尾:

往期回顾:

《告别 “会用不会讲”:C++ string 底层原理拆解 + 手撕实现,面试 / 开发都适用》

结语:回溯 C++98/03 string 的拷贝与 swap 机制,既是理解早期内存管理智慧的钥匙,也为掌握现代 C++ 容器设计打下根基。

✨把这些内容吃透超牛的!放松下吧✨
ʕ˘ᴥ˘ʔ
づきらど


Read more

Node.js 所有主要版本的发布时间、稳定版本(Stable)和长期支持版本(LTS) 的整理

Node.js 所有主要版本的发布时间、稳定版本(Stable)和长期支持版本(LTS) 的整理

以下是 Node.js 所有主要版本的发布时间、稳定版本(Stable)和长期支持版本(LTS) 的整理,涵盖从早期版本到当前最新版本的信息。 📅 Node.js 版本发布规律 * 每 6 个月发布一个新主版本(偶数月) * 偶数版本号(如 v14, v16, v18, v20)进入 LTS(长期支持) * 奇数版本号(如 v15, v17, v19)为 Current(开发版本),仅在发布后 6 个月内受支持 * LTS 版本通常支持 30 个月:6 个月“Active LTS”,24 个月“Maintenance LTS” 🔢 主要版本及其生命周期信息

By Ne0inhk
Spring Boot多模块(双后端服务)整合Smart-Doc实战,Smart-Doc 真香!

Spring Boot多模块(双后端服务)整合Smart-Doc实战,Smart-Doc 真香!

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Micro麦可乐的博客 🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战 🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战 🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解 🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用 🍎 《前端技术》专栏以实战为主介绍日常开发中前端应用的一些功能以及技巧,均附有完整的代码示例 ✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧 💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程 🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整 👍《Spring Security》专栏中我们将逐步深入Spring Security的各个

By Ne0inhk
分享一套优质的微信小程序校园失物招领系统(SpringBoot后端+Vue管理端)

分享一套优质的微信小程序校园失物招领系统(SpringBoot后端+Vue管理端)

大家好,我是锋哥,看到一个不错的微信小程序校园失物招领系统(SpringBoot后端+Vue管理端),分享下哈。 项目介绍 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱,出错率高,信息安全性差,劳动强度大,费时费力等问题,采用校园失物招领系统可以有效管理,使信息管理能够更加科学和规范。 校园失物招领系统使用Java语言进行编码,使用Mysql创建数据表保存本系统产生的数据。系统可以提供信息显示和相应服务,其管理校园失物招领系统信息,查看校园失物招领系统信息,管理校园失物招领系统。 总之,校园失物招领系统集中管理信息,有着保密性强,效率高,存储空间大,成本低等诸多优点。它可以降低信息管理成本,实现信息管理计算机化。 源码下载 链接:https://pan.baidu.com/s/1CwHLHe11xreoL5Zr7xKJ6Q?pwd=1234 提取码:1234 系统展示 核心代码 package com.controller;

By Ne0inhk
Spring Boot AOP(五) 高级特性与源码实践

Spring Boot AOP(五) 高级特性与源码实践

博主社群介绍: ① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。 ② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。 ③ 群内也有职场精英,大厂大佬,跨国企业主管,可交流技术、面试、找工作的经验。 进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬,进群赠送ZEEKLOG评论防封脚本,送真活跃粉丝,助你提升文章热度。 群公告里还有全网大赛约稿汇总/博客提效工具集/ZEEKLOG自动化运营脚本 有兴趣的加文末联系方式,备注自己的ZEEKLOG昵称,拉你进群,互相学习共同进步。 文章目录 * Spring Boot AOP(五) 高级特性与源码实践 * 1. 高级特性概述 * 2. 自定义 Pointcut * Mermaid 图:自定义 Pointcut 匹配流程 * 3. 自定义 Advice

By Ne0inhk