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

【C++】weak_ptr、循环引用与线程安全

shared_ptr解决了共享所有权的问题,但引入了一个新坑:循环引用。当两个对象互相持有对方的shared_ptr,引用计数永远降不到零,资源就永远不会释放。weak_ptr正是为此而生。

目录

1. 循环引用:图说明问题

2. weak_ptr:打破循环

3. 线程安全:引用计数要原子

4. shared_ptr的另几个常用能力

5. 内存泄漏的最后一道防线


1. 循环引用:图说明问题

常见场景:双向链表节点、树节点中存父子指针、观察者模式中Subject和Observer互指。

cpp

struct ListNode { int _data; shared_ptr<ListNode> _next; shared_ptr<ListNode> _prev; ~ListNode() { cout << "~ListNode()" << endl; } }; int main() { shared_ptr<ListNode> n1(new ListNode); shared_ptr<ListNode> n2(new ListNode); // 此时 n1引用计数1,n2引用计数1 n1->_next = n2; // n2引用计数变为2 n2->_prev = n1; // n1引用计数变为2 // main离开后n1、n2析构,计数各减一,都变成1 // 谁都没到零,ListNode永不被释放 }

两节点互相“拽”着对方,形成一个死锁。根源在于_next_prev参与了资源所有权的管理,但它们不应该拥有所属节点的生命周期决定权——它们只是引用而已。

2. weak_ptr:打破循环

weak_ptr专门用于绑定shared_ptr,但不增加引用计数。它不支持直接管理资源(没有RAII),也没有operator*operator->。因为它不控制资源的生命周期,在资源已被释放后访问很危险,所以它提供了两个关键接口:

  • expired():检查引用的资源是否还存在。

  • lock():返回一个指向资源的shared_ptr。如果资源还在,返回的shared_ptr非空且安全访问;如果资源已被释放,返回空shared_ptr

cpp

struct ListNode { int _data; weak_ptr<ListNode> _next; // 改用weak_ptr weak_ptr<ListNode> _prev; ~ListNode() { cout << "~ListNode()" << endl; } }; // n1->_next = n2; // 此时n2引用计数不增加,仍为1 // main结束后n1、n2正常析构

weak_ptr的构造只接受shared_ptr或另一个weak_ptr,不接受裸指针。这不是能力限制,是语义设计——你不拥有资源,也就不能凭空创建一个管理关系的入口。

需要访问时,先lock()

cpp

weak_ptr<ListNode> wp = n1; if (auto sp = wp.lock()) { sp->_data = 10; // 安全访问 }

lock()返回的shared_ptr在作用域内持有引用计数,保证访问期间资源不会被释放,这是线程安全使用weak_ptr的基本模式。

3. 线程安全:引用计数要原子

shared_ptr的引用计数存放在堆上,多个shared_ptr对象在不同线程中进行拷贝和析构,会并发修改同一个计数,存在数据竞争。

最简单的修复是在模拟实现中将int* _pcount替换为atomic<int>* _pcount,核心操作变成原子增减:

cpp

// 构造函数 _pcount = new atomic<int>(1); // 拷贝构造 (*_pcount)++; // release if (--(*_pcount) == 0) { /* 释放 */ }

标准库的shared_ptr对引用计数的操作是线程安全的,但管理对象本身的操作不是。如果多个线程同时修改同一个shared_ptr指向的对象内部数据,仍然需要外部同步。通俗来说:shared_ptr保证“自己不会因为并发拷贝/析构坏掉”,但不保证“里面的对象线程安全”。后者是使用者的责任。

4. shared_ptr的另几个常用能力

shared_ptr支持operator bool,可以直接放在if里判断是否管理着资源:

cpp

shared_ptr<int> sp; if (!sp) cout << "empty" << endl;

make_shared<T>(args...)比直接new更好:一次内存分配同时容纳对象和控制块,效率高,也能避免newshared_ptr构造之间的异常导致泄漏。

自定义删除器让shared_ptr不仅能管内存,还能管文件、socket等任意资源:

cpp

shared_ptr<FILE> sp(fopen("test.cpp", "r"), [](FILE* f) { cout << "fclose" << endl; fclose(f); });

这本质上是RAII思想通过模板和函数对象实现的泛化——不再限于delete这一种释放方式。对于unique_ptr,同样支持删除器,只是语法上作为模板参数给出,略有不同。

5. 内存泄漏的最后一道防线

技术层面讲完了,补充一个工程层面的常识。

内存泄漏不是指物理内存消失了,而是程序分配了一段内存后失去了对它的追踪,这块内存既用不到也放不掉。短期运行的程序,进程退出时操作系统会回收所有内存,泄漏后果不大;但长期运行的进程(服务器、数据库、系统服务),泄漏会累积,最终内存耗尽。

避免泄漏的核心策略就两条:

  • 事前预防:用智能指针和RAII在设计层面消除手动释放的必要。

  • 事后检测:用valgrind、Visual Leak Detector等工具定期排查,尤其在版本上线前。

但检测工具只是安全网,不是救命稻草。设计阶段就把资源所有权理清楚,比任何工具都靠谱。

智能指针本身不是银弹。shared_ptr用得过滥,会导致对象生命周期模糊、循环引用、不必要的原子操作开销。一个简单的判断原则:默认用unique_ptr,只有当确实有多个所有者共享同一资源时才换shared_ptrweak_ptr永远作为辅助角色出现,解决特定的引用关系问题,不应独立承担资源管理职责。

http://www.jsqmd.com/news/908834/

相关文章:

  • 如何在3分钟内将Windows电脑变成免费WiFi热点:VirtualRouter终极指南
  • 免费去水印的软件免费下载|AI去水印工具实测推荐
  • RePKG终极指南:5步解锁Wallpaper Engine壁纸资源
  • NCMDump终极指南:3步解锁网易云音乐加密音频文件
  • 2026年诸暨市正规上门黄金白银回收品牌门店名录:K金+铂金+金条+银条回收门店联系方式推荐+指南 - 前途无量YY
  • 2026年最新阳春市黄金回收白银回收铂金回收靠谱店铺权威排行榜:纯金+金条+银条+钯金 门店地址及联系方式推荐 - 亦辰小黄鸭
  • 2026楚雄市本地人必选的公共卫生检测专业机构TOP5推荐!美容院、足疗店、酒店宾馆卫生检测、许可证办理,正规CMA资质检测公司排名推荐 (2026年5月商铺卫生办证最新深度调研方案) - 一修哥咨询
  • RoboMimic Deploy使用笔记
  • 图像搜索引擎背后的秘密:用Python颜色直方图实现‘以图搜图’原型
  • 2026年驻马店市正规上门黄金白银回收品牌门店名录:K金+铂金+金条+银条回收门店联系方式推荐+指南 - 前途无量YY
  • c语言练习:关机程序
  • 山东EPDM塑胶厂家排行:彩色颗粒定制能力实测对比 - 奔跑123
  • 基于大语言模型与Vue ue 3的智能简历生成系统设计与实现
  • 2026年最新阳江市黄金回收白银回收铂金回收靠谱店铺权威排行榜:纯金+金条+银条+钯金 门店地址及联系方式推荐 - 亦辰小黄鸭
  • 终极指南:如何免费在Windows上创建高性能虚拟显示器
  • 量子模拟中的Trotter步进与电路压缩技术
  • 免费开源AMD Ryzen调试工具:SMUDebugTool完全指南
  • 对计算机视觉的基本认知三(表征学习与变换)
  • 三步掌握抖音批量下载助手:告别手动收集的繁琐时代
  • 视频去水印的软件哪个好用又免费?2026实测推荐
  • DS4Windows电池管理终极指南:告别游戏中断的完整解决方案
  • 2026年最新阳泉市黄金回收白银回收铂金回收靠谱店铺权威排行榜:纯金+金条+银条+钯金 门店地址及联系方式推荐 - 亦辰小黄鸭
  • 2026年庄河市正规上门黄金白银回收品牌门店名录:K金+铂金+金条+银条回收门店联系方式推荐+指南 - 前途无量YY
  • Linux调试说明——CAN设备收发测试
  • VL31N/VL32N之外:SAP内部交货单BAPI性能对比与选型建议(GN_DELIVERY_CREATE vs BAPI_DELIVERYPROCESSING_EXEC)
  • Flutter+HarmonyOS跨端实战—第02篇:路由与状态管理实战
  • 供应链管理:理解链主企业 / 谁可以成为链主企业
  • RTX51信号量机制与任务调度优化策略
  • 2026年资阳市正规上门黄金白银回收品牌门店名录:K金+铂金+金条+银条回收门店联系方式推荐+指南 - 前途无量YY
  • 2026年最新仪征市黄金回收白银回收铂金回收靠谱店铺权威排行榜:纯金+金条+银条+钯金 门店地址及联系方式推荐 - 亦辰小黄鸭