当前位置: 首页 > backend >正文

优秀开源内容转自公众号后端开发成长指南

背景:在C++中,手动管理资源(new/delete)容易出错,导致:内存泄漏,重复释放,异常安全等问题。

为了解决这些问题,C++11引入了智能指针:

std::unique_ptr:独占所有权,std::shared_ptr 共享所有权,通过引用计数来管理生命周期

原理:

unique_ptr:目标是独占所有权,不可复制,只能移动(move)

使用场景:资源唯一所有权,RAII风格自动释放;

核心问题是:避免内存泄漏,支持移动语义。

核心原理:

1.独占所有权:唯一指针拥有资源,拷贝被禁用

2.移动语义:通过移动实现资源转移:

3.RAII:生命周期结束自动释放。

3.性能特点:

内存占用小(只存储原始指针和删除器)

无额外引用计数开销

编译器开销低

异常安全,必变资源泄漏;

shared_ptr:目标是多方共享资源,引用计数控制生命周期。

使用场景:多线程共享对象,缓存管理。

核心问题:

自动管理生命周期;处理多线程环境下的引用计数(atomic)

避免循环引用问题

1.内部结构:核心在于引用计数和控制块。

shared_ptr<T>
├── T* ptr           // 实际对象指针
└── ControlBlock* cb // 引用计数和删除器

控制块结构示例

2.核心逻辑:

1)构造shared_ptr:初始化use_count = 1;

2) 拷贝shared_ptr:use_count++(原子操作)

3)析构shared_ptr:use_count--,若为0调用删除器销毁对象;

weak_ptr:不增加use_count,仅增加weak_count,用于解决循环引用。

3.关键实现细节:

线程安全:std::atomic 保证引用计数在多线程下正确;

控制块分离:

对象和控制快分离,可以支持make_shared内联分配(减少内存碎片)

循环引用问题:

两个shared_ptr互相循环引用会导致引用计数不为0

需要weak_ptr解决;

4.性能分析:

unique_ptr vs shared_ptr

1.内存占用:

小,指针+删除器; 控制块额外开销,atomic计数

2. 拷贝/移动开销

禁止拷贝,移动开销小; 拷贝需要原子操作,移动开销小

3.多线程安全

依赖外部保护; 引用计数原子操作保证安全

关键区别:引用计数的原子性

cpp

// ❌ unique_ptr - 所有权转移不是线程安全的
class BadExample {std::unique_ptr<Data> data;
public:// 线程1调用void thread1() {auto temp = std::move(data); // 危险!没有同步// data现在是nullptr}// 线程2调用void thread2() {if (data) { // 竞态条件!data->process(); // 可能崩溃}}
};// ✅ shared_ptr - 引用计数操作是原子的
class GoodExample {std::shared_ptr<Data> data;
public:// 线程1调用void thread1() {auto local_copy = data; // 原子地增加引用计数if (local_copy) {local_copy->process(); // 安全使用}} // 原子地减少引用计数// 线程2调用  void thread2() {auto local_copy = data; // 原子地增加引用计数if (local_copy) {local_copy->process(); // 安全使用}} // 原子地减少引用计数
};

更好的对比示例

cpp

// unique_ptr - 必须用锁保护所有权转移
class TaskProcessor {std::unique_ptr<Task> current_task;std::mutex task_mutex;
public:void process() {std::unique_ptr<Task> local_task;{std::lock_guard<std::mutex> lock(task_mutex);local_task = std::move(current_task); // 必须在锁内移动}if (local_task) {local_task->execute();}}void setTask(std::unique_ptr<Task> task) {std::lock_guard<std::mutex> lock(task_mutex); // 必须加锁current_task = std::move(task);}
};// shared_ptr - 复制操作本身是线程安全的
class DataCache {std::shared_ptr<CachedData> cached_data;// 注意:这里不需要mutex保护shared_ptr的复制!
public:void updateCache(std::shared_ptr<CachedData> new_data) {cached_data = new_data; // 原子操作,无需加锁}std::shared_ptr<CachedData> getData() {return cached_data; // 原子操作,无需加锁}void process() {auto local_data = getData(); // 线程安全地获取副本if (local_data) {// 即使其他线程调用updateCache(),local_data仍然有效local_data->doWork(); }}
};

4.循环引用风险

无; 有,需要weak_ptr

5.适用场景:

独占资源 RAII; 多方共享对象管理,缓存,异步任务。

核心思想:能用 unique_ptr 就用 unique_ptr,能静态分析生命周期,避免 atomic 开销;需要多方共享才用 shared_ptr,并结合 weak_ptr 避免循环引用。

总结:

unique_ptr:

独占资源所有权,低开销,RAII自动释放

通过移动语义实现所有权转移

shared_ptr:共享资源,通过引用计数和控制块管理生命周期

支持多线程,但有性能开销

循环引用需要weak_ptr解决。

在分布式系统

hotspot 对象尽量用 unique_ptr

异步回调、共享上下文用 shared_ptr

一句话总结
“能唯一所有权就用 unique_ptr,必须共享就用 shared_ptr,控制引用计数就是控制你的性能。”

struct ControlBlock {std::atomic<size_t> use_count;   // 强引用计数std::atomic<size_t> weak_count;  // 弱引用计数Deleter deleter;                 // 删除器T* ptr;                          // 指向对象
};
http://www.xdnf.cn/news/19564.html

相关文章:

  • Java-114 深入浅出 MySQL 开源分布式中间件 ShardingSphere 深度解读
  • Linux 文本处理实战手册
  • 销售事业十年规划,并附上一套能帮助销售成长的「软件工具组合」
  • 爬虫实战练习
  • C 基础(1) - 初识C语言
  • 2025年数字化转型关键证书分析与选择指南
  • compile_commands.json 文件详解
  • Linux基础2
  • (3dnr)多帧视频图像去噪 (一)
  • GDAL 简介
  • C++ multiset数据结构的使用情况说明
  • 基于单片机智能饮水机/智能热水壶
  • 正式发布!2025AI SEO公司哪家专业?
  • 【数据分享】多份土地利用矢量shp数据分享-澳门
  • C# FlaUI win 自动化框架,介绍
  • 员工自愿放弃社保,企业给补贴合法吗?
  • Vue3 中 Proxy 在组件封装中的妙用
  • Windows 使用 Compass 访问MongoDb
  • 【HarmonyOS】一步解决弹框集成-快速弹框QuickDialog使用详解
  • 笔记:现代操作系统:原理与实现(1)
  • 卷积神经网络中的两个重要概念——感受野receptive filed和损失函数loss function
  • 【Element Plus `el-select` 下拉菜单响应式定位问题深度解析】
  • 刘洋洋《一笔相思绘红妆》上线,献给当代痴心人的一封情书
  • CUDA编程11 - CUDA异步执行介绍
  • Java 不支持在非静态内部类中声明静态 Static declarations in inner classes are not supported异常处理
  • elasticsearch中文分词器analysis-ik使用
  • Uniapp 生命周期详解:页面生命周期 vs 应用生命周期(附实战示例)
  • 大模型应用开发面试实录:LLM原理、RAG工程与多Agent场景化落地解析
  • gh-pages部署github page项目
  • DAY 20 奇异值SVD分解-2025.9.1