展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > C++实现简单的垃圾回收RAII方案 _ 计数指针原理【源码】

C++实现简单的垃圾回收RAII方案 _ 计数指针原理【源码】

C++实现简单的垃圾回收RAII方案 _ 计数指针原理【源码】 为什么 raw_ptr + delete 容易出 double-free 或 dangling pointer 说到底,裸指针手动管理生命周期,本质上就是把“谁该释放”和“何时释放”的决策权,完全交给了程序员。一旦对象被多个模块共享,或

本文目录

    C++实现简单的垃圾回收RAII方案 _ 计数指针原理【源码】

    C++实现简单的垃圾回收RAII方案 _ 计数指针原理【源码】

    为什么 raw_ptr + delete 容易出 double-free 或 dangling pointer

    说到底,裸指针手动管理生命周期,本质上就是把“谁该释放”和“何时释放”的决策权,完全交给了程序员。一旦对象被多个模块共享,或者程序执行中途因为异常跳出作用域,那个关键的delete就很容易被漏掉、被重复调用,甚至在对象早已销毁后,代码还在尝试解引用它。这里有个常见的误解:RAII本身并不解决共享所有权的问题,它只保证在单个作用域内资源能自动释放。而像std::shared_ptr这样的计数指针,才是对RAII理念的自然延伸——它把“引用计数”这个状态本身,也纳入了资源管理的范畴。

    实际开发中,下面这些错误现象屡见不鲜:

    • 函数返回了一个在局部new出来的对象指针,调用方却忘了delete,结果就是内存泄漏。
    • 两个std::shared_ptr虽然指向同一块原始内存,但却是分别用new构造的(非同源),导致引用计数错乱,最终引发double-free。
    • 循环引用,比如A持有B的std::shared_ptr,B也持有A的,导致引用计数永远无法归零,对象无法被析构。

    如何手写一个最小可用的 ref_ptr(非线程安全版)

    要实现一个最简可用的引用计数指针,核心离不开三要素:指向对象的原始指针、一个独立的引用计数器、以及封装在析构函数里的资源释放逻辑。这里有几个关键点需要注意:计数器不能放在对象内部(那是侵入式方案,不够通用),也不能和对象共用同一块内存(除非定制operator new),否则在delete对象时,计数器本身就无法被安全释放了。

    具体操作上,有这么几个要点:

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

    • 计数器必须动态分配:使用new size_t(1)来确保它的生命周期独立于它所托管的对象。
    • 拷贝构造与赋值是关键:执行拷贝时,要先对原指针的计数器执行--(*cnt),然后检查计数是否归零,以此来决定是否需要delete托管对象和计数器本身。
    • 移动语义需显式置空:实现移动操作时,一定要记得将右值(被移动对象)的指针和计数器置空,防止后续析构函数误删资源。
    • 接口行为需一致:提供get()、operator->等接口时,其行为应当与std::shared_ptr保持一致,降低使用者的心智负担。

    下面是一个简化版的关键路径代码示例:

    template
    class ref_ptr {
        T* ptr_;
        size_t* cnt_;
    public:
        explicit ref_ptr(T* p = nullptr) : ptr_(p), cnt_(p ? new size_t(1) : nullptr) {}
    
        ref_ptr(const ref_ptr& other) : ptr_(other.ptr_), cnt_(other.cnt_) {
            if (cnt_) ++(*cnt_);
        }
    
        ~ref_ptr() {
            if (cnt_ && --(*cnt_) == 0) {
                delete ptr_;
                delete cnt_;
            }
        }
    
        T* get() const { return ptr_; }
        T& operator*() const { return *ptr_; }
        T* operator->() const { return ptr_; }
    };

    ref_ptr 和 std::shared_ptr 在 reset / release 行为上的关键差异

    标准库的std::shared_ptr::reset()设计得很周全:它会先减少旧资源的引用计数,然后再去接管新对象。而手写版本如果没实现类似的逻辑,直接进行ptr_ = new_obj; cnt_ = new_cnt;这样的赋值,就会跳过对旧资源的清理步骤,从而导致内存泄漏或悬垂指针。

    在实现这些功能时,有几个坑特别容易踩到:

    • 用赋值替代reset():如果没实现专门的reset()方法,靠拷贝赋值来替代,可能会触发不必要的拷贝构造和析构,不仅性能差,还会让引用计数的逻辑变得复杂和沉重。
    • 实现reset(nullptr)时忘记置空cnt_:这会导致后续析构函数仍然尝试去delete cnt_,访问野指针,引发未定义行为。
    • 误以为需要release():对于计数指针来说,语义上并不支持“交出所有权但不减少引用计数”这种操作,这会破坏RAII的基本契约,所以通常不应该提供release()方法。
    • 缺乏自定义删除器支持:简易实现往往不支持自定义删除器(Deleter),因此无法处理那些由malloc分配,或者需要调用CloseHandle等特定函数来释放的资源。

    循环引用真的只能靠 std::weak_ptr 解?手写怎么加

    弱引用(weak_ptr)并不是“另一个拥有所有权的指针”,它本质上是对同一块控制块(包含引用计数器)的**非拥有式观察者**。它不参与强引用计数(cnt_)的增减,只在需要时尝试“升级”为强引用(即检查对象是否还存活)。因此,要实现弱引用,就必须在控制块里额外维护一个“弱计数”字段,用来记录有多少个weak_ptr正在观察这个计数器。

    自己动手实现的话,必须把握住这几个要点:

    • 扩展计数器结构:计数器需要从单个size_t扩展为至少包含strong_count和weak_count两个字段的结构体。
    • 析构逻辑分离:weak_ptr析构时,只减少weak_count;只有当strong_count == 0 && weak_count == 0两个条件同时满足时,才能安全地释放计数器内存本身。
    • 安全地“升级”:lock()方法需要原子性地读取strong_count并判断是否大于0,只有在对象存活时,才构造一个新的ref_ptr(此时才会增加strong_count)。
    • 明确并发限制:即使你实现的是非线程安全版本,也必须在代码中明确标注“不保证多线程并发调用的安全性”,防止使用者误将其用于异步场景,导致难以调试的问题。

    走到这一步,其复杂度已经逼近std::shared_ptr实现的下限了。对于绝大多数项目而言,直接使用标准库是更稳健的选择。自己实现引用计数指针,通常目的仅限于深入理解其原理,或者是为了嵌入那些无法使用STL的受限环境,而不是为了替代标准库。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 C++
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    Beamer 4 macOS版
    Beamer 4 macOS版

    Beamer 4是面向macOS的本地视频投屏工具,可将Mac中的影片投放到Apple TV、Chromecast及兼容设备,支持常见格式、多类字幕、环绕声、播放列表和电视遥控操作。

    Boom 3D macOS版
    Boom 3D macOS版

    Boom 3D macOS版是一款系统级音效增强工具,可为音乐、电影、游戏和流媒体提供3D虚拟环绕声、31段均衡器、音量增强及应用独立音量控制,并支持本地播放器与多种音频输出设备。

    Boris FX macOS版
    Boris FX macOS版

    Boris FX macOS版是一套面向剪辑、合成、调色及动态图形工作的专业后期工具,涵盖视觉特效、平面与三维跟踪、转描、画面修复、粒子动画和音频清理,可配合多种主流宿主软件使用。

    Capto macOS版
    Capto macOS版

    Capto 是面向 macOS 的屏幕截图、高清录屏与媒体编辑工具,支持区域及整屏捕获、网页长截图、双音轨处理、图片和视频标注、素材分类与多渠道分享,适合教师、学生、内容创作者及需要制作演示教程的用户。

    ChemDraw macOS版
    ChemDraw macOS版

    ChemDraw macOS版是一款面向化学学习、科研和制药工作的专业结构绘图工具,可创建分子、反应及生物聚合物图形,并提供结构整理、格式转换和科研成果展示能力。

    Cursor Crane macOS版
    Cursor Crane macOS版

    Cursor Crane 是一款仅面向 macOS 的键盘操控效率工具,可通过提示标签、网格、文字查找和窗口模式完成点击、滚动、定位与切换,并支持屏幕内容提取、脚本及工作流扩展。

    Deep Freeze 冰点还原 macOS版
    Deep Freeze 冰点还原 macOS版

    Deep Freeze 冰点还原 macOS版通过冻结系统配置,让受保护的Mac在重新启动后回到预设状态,并提供解冻空间、维护计划、密码保护及Apple Remote Desktop管理能力。

    Focusky macOS版
    Focusky macOS版

    Focusky macOS版是一款面向教学课件、商务汇报、产品展示和动画宣传内容的演示制作工具。它通过无限画布、路径编排、缩放旋转转场及多媒体编辑,将传统逐页幻灯片转化为更具空间感的动态演示。

    Folder Colorizer 2 macOS版
    Folder Colorizer 2 macOS版

    Folder Colorizer 2 macOS版是一款直观的文件夹外观定制工具,可更换颜色,添加表情、贴纸及图片背景,并支持批量处理、智能推荐和恢复默认样式,帮助用户更快辨认工作、学习与生活资料。

    WINDOWS 更多
    Fuzor Windows版
    Fuzor Windows版

    Fuzor Windows版是一套面向建筑、工程与施工团队的BIM/VDC平台,可汇集多来源模型和进度数据,完成实时可视化、4D施工推演、场地物流规划、问题检查、成果演示及团队协同。

    Gety Windows版
    Gety Windows版

    Gety Windows版是一款本地AI文件搜索工具,可索引电脑中的文档和图片,通过全文搜索、语义检索与OCR快速定位内容,并提供原版式预览、筛选和AI工具连接功能。

    iMazing Windows版
    iMazing Windows版

    iMazing Windows版是一款面向iPhone、iPad和iPod用户的本地设备管理工具,可在电脑上完成多版本备份、照片与音乐传输、信息导出、应用数据管理以及新旧设备迁移。

    Mercalli Windows版
    Mercalli Windows版

    Mercalli是一款面向Windows用户的专业视频稳定与画面修复工具,可分析手持、运动相机、无人机和长焦素材中的抖动,校正滚动快门及CMOS果冻效应,并提供曝光、色彩、锐度和镜头画面优化功能。

    NiceLabel Windows版
    NiceLabel Windows版

    NiceLabel是面向Windows平台的商业条码标签设计与打印工具,可制作文字、图像、条码及变量数据标签,并支持数据库连接、批量打印、打印自动化和集中管理,适用于制造、仓储、物流及零售等场景。

    pdfFactory Windows版
    pdfFactory Windows版

    pdfFactory是一款面向Windows的PDF虚拟打印机,可从支持打印的应用程序创建PDF,在保存前完成即时预览、页面排序、旋转、删除及多文档合并,并支持字体嵌入、邮件发送等办公功能。

    Polarr Windows版
    Polarr Windows版

    Polarr Windows版是一款面向摄影爱好者与内容创作者的照片编辑工具,提供曝光和色彩调整、曲线、HSL、滤镜、局部蒙版、人像修饰、叠加效果及批量导出等功能,适合日常修图、社交媒体配图和较细致的影像后期处理。

    AIDA64 Windows版
    AIDA64 Windows版

    AIDA64是一款面向Windows电脑用户的系统信息、硬件诊断与基准测试工具,可识别处理器、主板、显卡、存储设备和系统组件,并实时监控温度、电压、功耗及风扇转速,适合装机验收、性能比较和稳定性排查。

    Portraiture Windows版
    Portraiture Windows版

    Portraiture Windows版是一款面向人像摄影后期的智能润饰插件,可在Photoshop、Lightroom Classic和Affinity中完成皮肤平滑、AI区域识别、肤色统一及补光处理,

    priPrinter 7 Windows版
    priPrinter 7 Windows版

    priPrinter 7 Windows版是一款虚拟打印机与打印预览工具,可接收其他程序的打印任务,在输出前调整页面顺序、边距与版式,并添加水印、页码或批注。专业版还支持文本修正、内容脱敏、打印历史和PDF发布。

    PSD Manager Windows版
    PSD Manager Windows版

    PSD Manager是适用于Windows版Autodesk 3ds Max的渲染后期插件,可把画面、渲染元素、对象及材质蒙版整理成分层PSD或PSB文件,便于在Photoshop、Affinity Photo和After Effects

    RayFire Windows版
    RayFire Windows版

    RayFire是运行于Windows版Autodesk 3ds Max中的破碎与刚体动力学插件,集成实时Voronoi切割、交互式拆除、爆炸、裂纹、缓存和体素等工具,适合影视特效、游戏动画及建筑坍塌镜头制作。