0

0

c++如何实现简单的垃圾回收机制_c++ 引用计数与自动内存管理策略【教程】

穿越時空

穿越時空

发布时间:2026-01-05 11:27:22

|

657人浏览过

|

来源于php中文网

原创

C++标准不提供垃圾回收,引用计数(如std::shared_ptr)仅为RAII式确定性释放,并非真正GC;它无法解决循环引用、无堆扫描能力、有性能开销且不管理非new内存或非内存资源。

c++如何实现简单的垃圾回收机制_c++ 引用计数与自动内存管理策略【教程】

C++ 标准本身不提供垃圾回收(GC),但可以用引用计数实现类 GC 的自动内存管理效果——关键在于:它不是真正的 GC,而是确定性、可预测的资源释放;用错场景反而会引发循环引用或性能问题。

为什么不能直接用 std::shared_ptr 当“垃圾回收器

std::shared_ptr 是引用计数智能指针,但它不解决循环引用,也不扫描堆内存。它只是在引用数归零时立即调用 delete,属于 RAII 范畴,不是 GC。

  • 循环引用时,两个对象互相持有 shared_ptr,引用计数永不为 0,内存泄漏
  • 频繁拷贝 shared_ptr 会带来原子操作开销(尤其在多线程下)
  • 无法回收原始裸指针、malloc 分配的内存、或非 new 构造的对象
  • 不处理对象、全局对象、或文件句柄等非内存资源(除非你自定义 deleter)

手动实现轻量引用计数类的关键点

自己写一个最小可用的引用计数指针,能帮你理解底层逻辑,也便于定制行为(比如日志、调试计数、弱引用支持)。

template
class RefCountPtr {
    T* ptr_;
    size_t* count_;
void release() {
    if (count_ && --(*count_) == 0) {
        delete ptr_;
        delete count_;
    }
}

public: explicit RefCountPtr(T* p = nullptr) : ptr(p), count(p ? new size_t(1) : nullptr) {}

RefCountPtr(const RefCountPtr& other) : ptr_(other.ptr_), count_(other.count_) {
    if (count_) ++(*count_);
}

RefCountPtr& operator=(const RefCountPtr& other) {
    if (this != &other) {
        release();
        ptr_ = other.ptr_;
        count_ = other.count_;
        if (count_) ++(*count_);
    }
    return *this;
}

~RefCountPtr() { release(); }

T& operator*() const { return *ptr_; }
T* operator-youjiankuohaophpcn() const { return ptr_; }

};

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

Veo
Veo

Google 最新发布的 AI 视频生成模型

下载
  • 必须用 size_t* 单独分配计数器,不能和对象布局耦合(否则无法通用)
  • 拷贝构造/赋值中要判空,避免对 nullptr 解引用或递增空指针
  • 析构时只负责释放计数器和对象,不负责重置 ptr_(这是安全的,因对象已销毁)
  • 没实现 weak_ptr 等价物,所以仍无法破循环引用

如何检测和打破循环引用

循环引用不是语法错误,运行期才暴露为内存泄漏。靠工具或设计约束来预防更实际。

  • std::weak_ptr 替代部分 shared_ptr:比如观察者模式中,被观察者持 shared_ptr,而观察者内部用 weak_ptr 回调
  • 静态分析:Clang 的 -Wlifetime 可捕获部分悬垂引用,但对跨对象循环无能为力
  • 运行时调试:重载 operator new + 全局计数器,配合 atexit() 检查未释放对象数量
  • 设计上规避:用 ID 或句柄(int)代替裸指针/智能指针传递,由中心容器管理生命周期

什么场景下真该考虑外部 GC(如 Boehm GC)

只有当你明确需要“不可预测但自动”的回收语义,且能接受限制时,才引入第三方 GC。

  • 嵌入脚本解释器(如用 C++ 实现 Lua host),需托管脚本对象生命周期
  • 遗留代码大量使用 malloc/free,又不愿重构为 RAII
  • 算法原型阶段,优先保证逻辑正确,暂不优化内存路径

Boehm GC 是保守式 GC,它可能把栈上一个整数误认为指针,从而漏回收真实对象;它不调用析构函数,所以不能用于管理含资源(文件、锁、GPU buffer)的对象——这点常被忽略。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

195

2023.11.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

314

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

526

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

49

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

191

2025.08.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

379

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

566

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

379

2023.07.18

mc.js网页版入口地址大全
mc.js网页版入口地址大全

本专题整合了mc.js网页版入口地址大全以及mc.js1.8.8版本汇总,阅读专题下面的文章了解更多详细内容。

34

2026.01.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.3万人学习

Pandas 教程
Pandas 教程

共15课时 | 0.9万人学习

ASP 教程
ASP 教程

共34课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号