智能指针(三):实现篇 —— shared_ptr 的内部设计与引用计数机制
关键词控制块、引用计数、weak_ptr、原子操作、make_shared、循环引用适合人群已理解所有权模型与移动语义想深入理解 shared_ptr 内部实现的开发者一、为什么要单独研究 shared_ptr在前两篇我们讲清unique_ptr 独占所有权移动语义 所有权转移机制但 shared_ptr 不一样。它允许auto p1 std::make_sharedStudent(18); auto p2 p1;多个对象共同持有同一资源。问题来了shared_ptr 如何保证最后一个释放时才 delete如何避免 double free为什么会有循环引用问题这一篇我们从实现角度拆解。二、shared_ptr 内部结构控制块Control Blockshared_ptr 并不只是一个“指针”。它内部包含两部分shared_ptr ↓ 指向对象的指针 控制块Control Block控制块通常包含- 强引用计数strong count - 弱引用计数weak count - 删除器deleter - 可能还有分配器信息可以简单理解为对象本体 控制块管理对象生命周期关键点shared_ptr 之间共享的不是对象本体而是共享“控制块”。三、引用计数是如何工作的当你写auto p1 std::make_sharedStudent(18); auto p2 p1;发生了什么1️⃣ 创建对象2️⃣ 创建控制块3️⃣ strong_count 14️⃣ p2 拷贝后 → strong_count 2当 p2 析构strong_count 1当 p1 析构strong_count 0 → 删除对象注意对象删除发生在 strong_count 0 时。四、弱引用计数是干什么的weak_ptr 的存在让控制块多了一层复杂性。控制块有两个计数类型含义strong_count拥有对象的数量weak_count观察对象的数量当 strong_count 0对象本体被 delete但控制块不会立即释放只有当strong_count 0 且 weak_count 0控制块才被销毁。这保证weak_ptr 仍然可以安全检测对象是否存在。五、为什么引用计数必须是原子操作shared_ptr 是线程安全的计数层面。多个线程可能同时拷贝 shared_ptr销毁 shared_ptr如果 strong_count 不是原子操作两个线程同时减 1可能只减一次或者减成负数或者提前 delete因此标准库实现中引用计数通常使用原子变量。这就是 shared_ptr 的额外成本。六、为什么 make_shared 更高效对比两种写法std::shared_ptrStudent p(new Student(18));和auto p std::make_sharedStudent(18);区别第一种分配一次对象内存再分配一次控制块内存两次堆分配第二种对象和控制块一起分配一次堆分配内存更紧凑性能更好工程最佳实践优先使用 make_shared。七、循环引用shared_ptr 最大的坑看一个经典例子class B; class A { public: std::shared_ptrB b; }; class B { public: std::shared_ptrA a; };当你创建auto a std::make_sharedA(); auto b std::make_sharedB(); a-b b; b-a a;发生了什么A 持有 Bstrong_count 1B 持有 Astrong_count 1当外部 shared_ptr 释放后A strong_count 1B strong_count 1永远不为 0。对象不会释放。这就是循环引用导致内存泄漏。八、weak_ptr 的真正价值解决方法class B { public: std::weak_ptrA a; };weak_ptr不增加 strong_count不参与对象生命周期只是观察者当需要访问对象时if (auto sp a.lock()) { // 安全访问 }这才是weak_ptr 存在的真正原因。九、shared_ptr 的工程代价shared_ptr 很强大但不是免费的。代价包括1️⃣ 原子引用计数开销2️⃣ 控制块额外内存3️⃣ 循环引用风险4️⃣ 复杂性提升因此工程实践中优先使用 unique_ptr只有在确实需要共享时才用 shared_ptr十、shared_ptr 的核心设计哲学shared_ptr 本质是“生命周期延迟释放机制”它解决的问题是多个模块共同拥有资源时如何安全释放它不适用于简单局部对象单一所有者场景性能极致场景十一、机制 实现串联总结到这里我们已经建立了三层理解第一篇认知层→ 所有权模型第二篇机制层→ 移动语义与所有权转移第三篇实现层→ 控制块 引用计数 weak_ptr现在你已经可以回答shared_ptr 如何避免 double free为什么有 strong / weak 两种计数为什么 make_shared 更优为什么循环引用会发生这已经进入STL 设计理解层。下一篇预告在第四篇我们会做体系整合现代 C 内存管理全景图内容包括栈 vs 堆RAIIRule of Fiveunique / shared / weak 使用准则工程最佳实践清单所有权模型完整结构图三篇铺垫之后进入体系。智能指针四体系篇 —— 现代 C 内存管理全景图

相关新闻

智能家居AI模型服务化:架构设计最佳实践

智能家居AI模型服务化:架构设计最佳实践

好的,这是一篇关于“智能家居AI模型服务化:架构设计最佳实践”的技术博客文章。 智能家居AI模型服务化:架构设计与最佳实践指南 副标题: 从原型到规模化部署,打造稳定、高效、智能的家居体验 摘要/引言 想象一下&…

2026/7/4 0:27:05 阅读更多 →
轴承故障诊断是工业设备监测的重要方向,今天咱们用MATLAB搞个玩具级别的轴承动力学模型。先甩开复杂的数学推导,直接上手写点能跑起来的代码

轴承故障诊断是工业设备监测的重要方向,今天咱们用MATLAB搞个玩具级别的轴承动力学模型。先甩开复杂的数学推导,直接上手写点能跑起来的代码

matlab球轴承动力学建模,最基础、简单的建模方法,以滚动体经过故障区域释放变形量描述受力,外圈内圈故障的球轴承动力学模型,适合初学者入门使用先设定轴承参数,假设外圈固定内圈旋转: R_outer 50e-3; …

2026/7/5 19:20:24 阅读更多 →
《信号与系统》欧拉公式的本质的角度的旋转

《信号与系统》欧拉公式的本质的角度的旋转

https://www.bilibili.com/video/BV1bF411P7RL 欧拉公式 eixcosxisinx 被誉为“上帝公式”,它的本质远不止是一个数学恒等式。它是数学结构深层统一性的体现,揭示了增长、旋转与振动之间内在的同一性。 如果要一言以蔽之,欧拉公式的本质是&…

2026/5/17 5:57:00 阅读更多 →

最新新闻

超棒!无需网络的离线地图应用 Organic Maps,2025 年安装量达 600 万!

超棒!无需网络的离线地图应用 Organic Maps,2025 年安装量达 600 万!

Organic Maps:隐私保护离线地图应用Organic Maps 是注重隐私保护的离线地图与 GPS 应用,适用于徒步、骑行和驾车场景。它免费、无广告、不追踪,由开源社区及创建 MapsWithMe/Maps.Me 应用的同一批开发者打造,数据源自 OpenStreetM…

2026/7/6 9:08:13 阅读更多 →
基于Go抓包+Python CNN的本地化异常流量检测工具(含GUI界面与预训练模型)

基于Go抓包+Python CNN的本地化异常流量检测工具(含GUI界面与预训练模型)

本文还有配套的精品资源,点击获取 简介:直接在本地运行的异常流量识别工具,底层用Go语言实现高效网络数据包捕获和会话解析,支持TCP/UDP/ICMP协议的实时流量提取、窗口计数、主机行为建模和服务识别;上层采用Python…

2026/7/6 9:08:13 阅读更多 →
MATLAB直接跑的7输入RBF回归工具:带数据、代码和结果图,开箱即用

MATLAB直接跑的7输入RBF回归工具:带数据、代码和结果图,开箱即用

本文还有配套的精品资源,点击获取 简介:这个MATLAB RBF神经网络回归工具包专为7个输入特征预测1个连续数值目标设计,不需要额外工具箱,兼容2018b及以上版本。主程序MainRBFR.m一键完成数据加载、RBF网络搭建、训练、测试和预测…

2026/7/6 9:08:13 阅读更多 →
Playwright网络请求拦截与模拟实战:从原理到六大应用场景详解

Playwright网络请求拦截与模拟实战:从原理到六大应用场景详解

1. 项目概述与核心价值 如果你正在用 Playwright 做自动化测试或者数据抓取,有没有遇到过这样的场景:测试一个下单流程,但支付接口总是不稳定,导致你的测试脚本动不动就失败;或者你想测试前端页面在网络超时或服务器返…

2026/7/6 9:04:10 阅读更多 →
PyTorch LSTM 多变量多任务预测:3种损失函数加权策略对比与代码实现

PyTorch LSTM 多变量多任务预测:3种损失函数加权策略对比与代码实现

PyTorch LSTM 多变量多任务预测:3种损失函数加权策略对比与代码实现在时间序列预测领域,多任务学习正逐渐成为提升模型性能的关键技术。当我们需要同时预测多个相关变量时,传统的单任务学习方法往往难以捕捉变量间的复杂关系。本文将深入探讨…

2026/7/6 9:04:10 阅读更多 →
Python Selenium自动化校园网登录:从环境搭建到打包部署全攻略

Python Selenium自动化校园网登录:从环境搭建到打包部署全攻略

1. 项目概述与核心价值 校园网登录,尤其是像深澜Srun这类需要跳转认证页面的系统,对于需要长时间保持网络连接的用户来说,是个不大不小的痛点。手动打开浏览器、输入账号密码、点击登录,这套流程每天重复几次,不仅繁琐…

2026/7/6 9:04:10 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻