手写mysharedptr是为避开shared_ptr的rtti、异常及线程开销,核心是独立控制块管理ref_count和t* ptr,拷贝/移动需正确维护control指针与计数,析构时判空并释放资源。

为什么不能直接用 shared_ptr?
如果你在写底层模块、嵌入式环境或教学代码,shared_ptr 可能带太多依赖(比如 RTTI、异常、线程安全开销),或者你只想理解引用计数机制本身。这时候手写一个最小可行的 MySharedPtr 是合理选择——它不追求工业级健壮性,但能跑通核心逻辑:构造、拷贝、析构、解引用。
MySharedPtr 必须管理的两个关键对象
引用计数不能只存一个整数;它必须和被管理对象生命周期解耦。典型做法是引入控制块(control block),里面放:ref_count、weak_count(可选)、以及指向实际对象的 ptr。但“简单”版本可以先省掉 weak_count,把控制块和对象合并在一块分配(即使用“intrusive”风格),或者用独立堆分配。
推荐起步方案:独立控制块 + 原始指针分离:
- 控制块结构体包含
int ref_count和T* ptr - 所有
MySharedPtr实例共享同一控制块指针(ControlBlock*) - 构造时 new 控制块;拷贝时
++control->ref_count;析构时--control->ref_count,为 0 则 deletecontrol->ptr和control
拷贝与移动的陷阱:别漏掉控制块的生命周期管理
常见错误是拷贝构造函数只复制了 ptr,没碰 control,导致多次 delete 同一对象;或者移动构造后原对象没置空,析构时又删一遍。
正确做法:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 拷贝构造/赋值:增加
control->ref_count,并让新实例指向同一control - 移动构造/赋值:把
other.control拿过来,再把other.control = nullptr(避免析构时误删) - 析构:仅当
control != nullptr && --control->ref_count == 0才 deletecontrol->ptr和control
注意:移动后原对象的 control 必须为 nullptr,否则其析构函数会尝试访问已释放内存。
解引用和空指针检查怎么做?
operator* 和 operator-> 必须先判空,否则野指针解引用会崩溃。控制块存在不代表 ptr 有效(比如 reset(nullptr) 后 control 还在,但 ptr 是 nullptr)。
建议实现:
operator->() { if (!control || !control->ptr) throw std::logic_error("dereferencing null MySharedPtr"); return control->ptr; }- 或者更轻量:直接
assert(control && control->ptr)(调试期),生产环境返回control ? control->ptr : nullptr并由用户负责检查 -
get()方法应返回control ? control->ptr : nullptr
别忘了提供 reset():释放当前对象(如果有的话),然后重新绑定新指针;若传 nullptr,只清理不分配。
最易忽略的是线程安全性——这个简易版默认不加锁,多线程同时拷贝/析构会破坏 ref_count。真要并发用,得在 ref_count 上套 std::atomic_int,且所有增减都用 fetch_add/fetch_sub。但这也意味着你已经踩进原子操作和内存序的坑里了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










