手写一个智能指针:从 unique_ptr 到 shared_ptr 的引用计数原理
博主介绍程序喵大人35 - 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章首发gzh见文末记得订阅专栏以防走丢C基础系列专栏C语言基础系列专栏C大佬养成攻略专栏C训练营个人网站C 内存管理的噩梦始于 new/delete 的手动配对止于智能指针的自动化革新。从 RAII资源获取即初始化的核心理念到 unique_ptr 的独占所有权再到 shared_ptr 的引用计数共享机制智能指针体系不仅解决了内存泄漏和悬空指针的顽疾更通过类型系统明确了资源所有权语义。本文将深入剖析智能指针的实现原理手写核心代码助你彻底掌握这一现代 C 基石技术。一、RAII资源管理的哲学基石RAIIResource Acquisition Is Initialization资源获取即初始化是 C 最重要的设计理念之一。其核心思想简单而强大资源的生命周期与对象的生命周期绑定。在对象构造时获取资源在对象析构时自动释放资源利用 C 栈对象的自动析构机制确保资源正确清理。classFileHandler{public:FileHandler(conststd::stringpath){fileHandlefopen(path.c_str(),r);// 构造即获取资源}~FileHandler(){if(fileHandle)fclose(fileHandle);// 析构必释放资源}private:FILE*fileHandle;};voidprocessFile(){FileHandlerfile(data.txt);// 自动打开// 使用文件...}// 离开作用域自动关闭即使发生异常RAII 的三大核心特性自动释放告别手动 delete / close异常安全即使发生异常也能正确回收资源禁止拷贝、支持移动资源只能有唯一所有者。这种设计让资源管理变得可预测、可维护是智能指针诞生的思想基础。二、unique_ptr独占所有权的轻量级守护者unique_ptr 体现了独占所有权的清晰语义。在任何时候只有一个 unique_ptr 可以指向一个给定的对象。它通过禁止拷贝构造函数和拷贝赋值运算符只提供移动构造函数和移动赋值运算符来实现所有权的唯一性。手写 unique_ptr 的核心实现templatetypenameTclassMyUniquePtr{private:T*ptr_;public:MyUniquePtr():ptr_(nullptr){}explicitMyUniquePtr(T*ptr):ptr_(ptr){}MyUniquePtr(constMyUniquePtr)delete;MyUniquePtroperator(constMyUniquePtr)delete;MyUniquePtr(MyUniquePtrother)noexcept:ptr_(other.ptr_){other.ptr_nullptr;}MyUniquePtroperator(MyUniquePtrother)noexcept{if(this!other){deleteptr_;ptr_other.ptr_;other.ptr_nullptr;}return*this;}~MyUniquePtr(){deleteptr_;}Toperator*()const{return*ptr_;}T*operator-()const{returnptr_;}T*get()const{returnptr_;}T*release(){T*tempptr_;ptr_nullptr;returntemp;}voidreset(T*ptrnullptr){deleteptr_;ptr_ptr;}explicitoperatorbool()const{returnptr_!nullptr;}};unique_ptr 的核心设计原则零开销抽象性能几乎等同于裸指针异常安全所有权转移过程不抛异常类型安全在编译期防止错误使用。这也是为什么在现代 C 中unique_ptr 是默认首选的智能指针。三、shared_ptr引用计数的共享所有权模型shared_ptr 允许多个指针共享同一个对象通过引用计数机制管理对象生命周期。当最后一个 shared_ptr 被销毁时对象才会被删除。其核心是控制块Control Block的设计。引用计数控制块的内存布局控制块是一个堆上的独立内存区域通常包含以下内容强引用计数use_count弱引用计数weak_count指向被管理对象的指针删除器deletertemplatetypenameTclassControlBlock{public:std::atomicsize_tuse_count{1};std::atomicsize_tweak_count{0};T*ptr{nullptr};std::functionvoid(T*)deleter;ControlBlock(T*p,conststd::functionvoid(T*)del):ptr(p),deleter(del?del:[](T*p){deletep;}){}};手写 shared_ptr 的核心实现templatetypenameTclassMySharedPtr{private:T*ptr_;ControlBlockT*ctrl_block_;voidincrement_ref(){if(ctrl_block_){ctrl_block_-use_count.fetch_add(1,std::memory_order_relaxed);}}voiddecrement_ref(){if(ctrl_block_){if(ctrl_block_-use_count.fetch_sub(1,std::memory_order_acq_rel)1){ctrl_block_-deleter(ctrl_block_-ptr);ctrl_block_-ptrnullptr;if(ctrl_block_-weak_count.load(std::memory_order_acquire)0){deletectrl_block_;}}}}public:MySharedPtr():ptr_(nullptr),ctrl_block_(nullptr){}explicitMySharedPtr(T*ptr):ptr_(ptr),ctrl_block_(newControlBlockT(ptr,nullptr)){}templatetypenameDeleterMySharedPtr(T*ptr,Deleter del):ptr_(ptr),ctrl_block_(newControlBlockT(ptr,del)){}MySharedPtr(constMySharedPtrother):ptr_(other.ptr_),ctrl_block_(other.ctrl_block_){increment_ref();}MySharedPtroperator(constMySharedPtrother){if(this!other){decrement_ref();ptr_other.ptr_;ctrl_block_other.ctrl_block_;increment_ref();}return*this;}MySharedPtr(MySharedPtrother)noexcept:ptr_(other.ptr_),ctrl_block_(other.ctrl_block_){other.ptr_nullptr;other.ctrl_block_nullptr;}~MySharedPtr(){decrement_ref();}Toperator*()const{return*ptr_;}T*operator-()const{returnptr_;}size_tuse_count()const{returnctrl_block_?ctrl_block_-use_count.load(std::memory_order_relaxed):0;}T*get()const{returnptr_;}voidreset(T*ptrnullptr){decrement_ref();if(ptr){ptr_ptr;ctrl_block_newControlBlockT(ptr,nullptr);}else{ptr_nullptr;ctrl_block_nullptr;}}};四、引用计数的线程安全性考量shared_ptr 的引用计数在多线程环境下必须是线程安全的标准库通过原子操作来保证这一点。关键实现细节包括使用 fetch_add / fetch_sub 操作引用计数增加引用时使用 memory_order_relaxed减少引用并可能释放资源时使用 memory_order_acq_relctrl_block_-use_count.fetch_add(1,std::memory_order_relaxed);if(ctrl_block_-use_count.fetch_sub(1,std::memory_order_acq_rel)1){// 释放资源}相比互斥锁原子操作的性能开销要小得多是 shared_ptr 设计中的关键优化点。五、循环引用问题的产生与解决当多个对象通过 shared_ptr 相互持有对方时会形成循环引用导致引用计数永远无法归零从而引发内存泄漏。典型的循环引用场景classB;classA{public:std::shared_ptrBb_ptr;};classB{public:std::shared_ptrAa_ptr;};voidcircularReference(){autoastd::make_sharedA();autobstd::make_sharedB();a-b_ptrb;b-a_ptra;}使用 weak_ptr 打破循环weak_ptr 不增加强引用计数只作为观察者存在。classB;classA{public:std::shared_ptrBb_ptr;};classB{public:std::weak_ptrAa_ptr;};voidfixedCircularReference(){autoastd::make_sharedA();autobstd::make_sharedB();a-b_ptrb;b-a_ptra;if(autoa_lockedb-a_ptr.lock()){// 对象仍然存在可以安全访问}}六、unique_ptr 与 shared_ptr 的核心差异对比维度unique_ptrshared_ptr所有权模型独占所有权共享所有权拷贝语义禁止拷贝仅支持移动支持拷贝内存开销单指针大小指针 控制块运行时开销几乎为零引用计数原子操作线程安全仅对象本身引用计数线程安全适用场景明确唯一所有者多对象共享资源选择原则默认使用 unique_ptr确实需要共享时再使用 shared_ptr出现双向引用时引入 weak_ptr优先使用 make_unique / make_shared 以减少内存分配次数。结语智能指针是现代 C 内存管理的核心工具。RAII 提供了思想基础unique_ptr 定义了清晰的独占所有权语义shared_ptr 则通过引用计数实现了安全的共享模型而 weak_ptr 负责解决循环引用这一经典难题。真正理解并掌握这些智能指针的实现原理才能在工程实践中写出健壮、高性能、可维护的 C 代码。码字不易欢迎大家点赞关注评论谢谢

相关新闻

基于Springboot售楼管理系统【附源码+文档】

基于Springboot售楼管理系统【附源码+文档】

💕💕作者: 米罗学长 💕💕个人简介:混迹java圈十余年,精通Java、小程序、数据库等。 💕💕各类成品Java毕设 。javaweb,ssm,springboot等项目&#…

2026/7/9 10:45:09 阅读更多 →
fastapi是什么框架?我看好多人提到了

fastapi是什么框架?我看好多人提到了

FastAPI 是一个现代、快速(高性能)的 Python Web 框架,专门用于构建 API(尤其是 RESTful API)。它基于 Python 3.6 的类型提示(type hints),使用 Starlette 和 Pydantic 构建。为什么…

2026/7/8 19:04:15 阅读更多 →
Go 微服务基于 Nacos 的服务发现 + 配置中心 + 服务治理 + K8s 融合全链路实战

Go 微服务基于 Nacos 的服务发现 + 配置中心 + 服务治理 + K8s 融合全链路实战

Go 微服务基于 Nacos 的服务发现 配置中心 服务治理 K8s 融合全链路实战目标:打造一套生产可落地的 Go 微服务治理体系 关键词:Nacos Go Config Center K8s 限流 熔断 负载均衡 优雅上下线这篇文章不是“怎么连上 Nacos”,而是回答…

2026/7/3 15:20:49 阅读更多 →

最新新闻

Polar Code 编解码 MATLAB 实现

Polar Code 编解码 MATLAB 实现

特点 Polar 编码(含冻结比特构造)SC(Successive Cancellation)解码 —— 理论基线CA-SCL(CRC-Aided SCL)解码 —— 5G NR 控制信道实际用的就是它AWGN BPSK 测试脚本 BER 曲线 代码风格延续你前面几轮的&…

2026/7/9 10:44:03 阅读更多 →
系规备考课程的底层架构——拆解金钟老师的教学逻辑

系规备考课程的底层架构——拆解金钟老师的教学逻辑

一门课程的价值,不仅在于它覆盖了多少知识点,更在于它的教学方法是否符合学员的学习规律。本文从教学逻辑的角度,分析金钟老师系规课程的架构设计。一、课程的整体架构课程按三阶段组织,分别是基础扫盲、案例攻坚、论文冲刺。这个…

2026/7/9 10:44:03 阅读更多 →
如何在Blender中高效使用MMD Tools插件:完整工作流指南

如何在Blender中高效使用MMD Tools插件:完整工作流指南

如何在Blender中高效使用MMD Tools插件:完整工作流指南 【免费下载链接】blender_mmd_tools MMD Tools is a blender addon for importing/exporting Models and Motions of MikuMikuDance. 项目地址: https://gitcode.com/gh_mirrors/bl/blender_mmd_tools …

2026/7/9 10:42:01 阅读更多 →
clip模型及论文精读-Learning Transferable Visual Models From Natural Language Supervision

clip模型及论文精读-Learning Transferable Visual Models From Natural Language Supervision

文章学习笔记根据B站【CLIP 论文逐段精读【论文精读】】 https://www.bilibili.com/video/BV1SL4y1s7LQ/?share_sourcecopy_web&vd_source62e4f3fd48d4ea21c7731322b8e5cb53以及作者:猛猿 链接:https://juejin.cn/post/7264503343996747830 来源&am…

2026/7/9 10:40:01 阅读更多 →
完整指南:如何用开源工具轻松提取网易游戏资源文件

完整指南:如何用开源工具轻松提取网易游戏资源文件

完整指南:如何用开源工具轻松提取网易游戏资源文件 【免费下载链接】unnpk 解包网易游戏NeoX引擎NPK文件,如阴阳师、魔法禁书目录。 项目地址: https://gitcode.com/gh_mirrors/un/unnpk 你是否对网易游戏《阴阳师》中的精美角色立绘和华丽特效充…

2026/7/9 10:40:01 阅读更多 →
082、EDVR实战:可变形卷积在视频超分中的高效应用与代码实现

082、EDVR实战:可变形卷积在视频超分中的高效应用与代码实现

082、EDVR实战:可变形卷积在视频超分中的高效应用与代码实现一个让我熬夜到凌晨三点的bug 去年做视频超分项目时,我遇到一个诡异现象:用EDVR训练了三天,验证集PSNR死活卡在28.5dB上不去。检查了数据加载、损失函数、学习率调度&am…

2026/7/9 10:37:59 阅读更多 →

日新闻

3大音乐平台逐字歌词完整解决方案:ESLyric-LyricsSource完全指南

3大音乐平台逐字歌词完整解决方案:ESLyric-LyricsSource完全指南

3大音乐平台逐字歌词完整解决方案:ESLyric-LyricsSource完全指南 【免费下载链接】ESLyric-LyricsSource Advanced lyrics source for ESLyric in foobar2000 项目地址: https://gitcode.com/gh_mirrors/es/ESLyric-LyricsSource 还在为Foobar2000找不到高质…

2026/7/9 0:01:04 阅读更多 →
ElegantBook封面定制揭秘:3个步骤打造专业级学术书籍

ElegantBook封面定制揭秘:3个步骤打造专业级学术书籍

ElegantBook封面定制揭秘:3个步骤打造专业级学术书籍 【免费下载链接】ElegantBook Elegant LaTeX Template for Books 项目地址: https://gitcode.com/gh_mirrors/el/ElegantBook 你是否曾经为学术书籍的封面设计而烦恼?想要一个既专业又美观的封…

2026/7/9 0:03:06 阅读更多 →
如何高效使用pyodbc:企业级数据库连接终极指南

如何高效使用pyodbc:企业级数据库连接终极指南

如何高效使用pyodbc:企业级数据库连接终极指南 【免费下载链接】pyodbc Python ODBC bridge 项目地址: https://gitcode.com/gh_mirrors/py/pyodbc 在当今数据驱动的商业环境中,企业级数据库连接已成为现代应用开发的核心需求。pyodbc作为一款强大…

2026/7/9 0:07:11 阅读更多 →

周新闻

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/8 16:14:06 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

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

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

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

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

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

2026/7/8 16:59:55 阅读更多 →

月新闻