0

0

c++中的写时复制(Copy-on-Write)技术_c++ COW字符串与智能指针实现【性能优化】

穿越時空

穿越時空

发布时间:2025-12-14 21:34:03

|

506人浏览过

|

来源于php中文网

原创

COW是一种延迟复制策略,多个对象共享数据直至写操作时才复制;C++11禁用std::string的COW因线程安全与标准冲突,现代改用SSO+深拷贝;shared_ptr体现指针级COW,对象级需cow_ptr封装;手写COW字符串因线程不友好、标准不符、调试困难等不再推荐。

c++中的写时复制(copy-on-write)技术_c++ cow字符串与智能指针实现【性能优化】

写时复制(Copy-on-Write,简称 COW)是一种经典的延迟复制优化策略:多个对象共享同一份底层数据,直到其中某个对象尝试修改时,才真正复制一份独立副本。它在 C++ 中曾广泛用于 std::string(C++98/03 时期)和自定义容器,以减少不必要的内存分配与拷贝开销。但需注意——C++11 标准明确禁止了 std::string 的 COW 实现,因其与多线程安全、迭代器失效、引用透明性等产生严重冲突;现代标准库普遍采用短字符串优化(SSO)+ 深拷贝策略。

COW 字符串的典型实现逻辑

一个手动实现的 COW string 需管理“引用计数 + 共享缓冲区”,核心在于:构造、拷贝不复制数据,赋值/修改前检查引用计数并按需分离。

  • 共享结构体:通常封装为带引用计数(atomic 或非 atomic,取决于线程模型)和字符数组的结构,如 struct string_data { size_t ref_count; char data[]; };
  • 拷贝构造/赋值:仅递增引用计数,指针指向同一块内存;不触发 new/memcpy
  • 写操作拦截:如 operator[] 非 const 版本、append()replace() 等,先调用 unshare() —— 若 ref_count > 1,则 new 新缓冲区、memcpy 原内容、递减旧计数、切换指针
  • 析构与释放:ref_count 减至 0 时 delete[] 缓冲区

COW 在智能指针中的自然体现

事实上,std::shared_ptr 就是 COW 思想的标准化、线程安全实现——但它复制的是“指针控制块”(含引用计数),而非所指对象本身。对象本身仍被共享,修改仍影响所有持有者。

  • 若你希望“对象级 COW”,即多个 shared_ptr 共享一份 T,但某次修改时自动克隆 T 的副本,需额外封装:例如定义 cow_ptr,内部持有一个 shared_ptr,并在写访问前调用 make_unique(*ptr) 复制对象
  • 常见模式:T& cow_ptr::operator*() { if (ptr.use_count() > 1) ptr = std::make_shared(*ptr); return *ptr; }
  • 注意:该方案适用于读多写少、T 可拷贝且拷贝成本可控的场景;频繁写入会抵消 COW 收益

为什么现代 C++ 不再推荐手写 COW 字符串?

不是技术不可行,而是代价常被低估:

PaperAiBye
PaperAiBye

支持近30多种语言降ai降重,并且支持多种语言免费测句子的ai率,支持英文aigc报告等

下载

立即学习C++免费学习笔记(深入)”;

  • 线程不友好:引用计数需原子操作(影响性能),且即使计数安全,data 内容读写仍需额外同步——否则出现 A 读、B 写、COW 分离中段,导致未定义行为
  • 不符合标准要求:C++11 要求 std::string::data() 返回可写指针,且允许通过 &s[0] 获取连续内存地址;COW 实现中,若未 unshare 就返回 data 指针,外部直接写入将破坏其他副本
  • 调试与可预测性差:复制开销从“恒定时间”变为“均摊但不可预测”,尤其在容器 resize、函数传参等隐式拷贝场景下,性能毛刺明显
  • SSO 更高效:多数短字符串(如标识符、错误码)根本无需堆分配;小对象拷贝比原子计数+条件分支更快

替代建议:轻量、安全、现代

真有共享只读+按需独占需求,优先考虑组合现有工具

  • 读多写少 → 用 std::shared_ptr 共享只读视图;写时构造新 string 并替换 shared_ptr
  • 需要原地修改隔离 → 用 std::optional<:string> 或自定义 handle 类,显式调用 clone_if_shared()
  • 高性能文本处理 → 考虑 absl::string_view + 显式 owned storage,或成熟库如 folly::fbstring(已弃用 COW,专注 SSO 和大字符串优化)
  • 自定义 COW 容器仅限封闭场景(如单线程配置缓存),务必用 std::atomic_size_t 管理计数,并禁用 data() 直接写入接口

基本上就这些。COW 是理解资源管理演进的好切口,但落地时要尊重标准约束与真实负载特征——省一次拷贝,不该以牺牲正确性与可维护性为代价。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

317

2023.08.02

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

743

2023.08.22

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

180

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

279

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

253

2025.06.11

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

121

2025.08.07

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

524

2023.09.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

257

2023.08.03

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

27

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 6.9万人学习

C 教程
C 教程

共75课时 | 4.1万人学习

C++教程
C++教程

共115课时 | 12.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号