3.1 KiB
3.1 KiB
RefCounted
命名空间: XCEngine::Core
类型: class
头文件: XCEngine/Core/RefCounted.h
描述: 一个侵入式原子引用计数基类,通过 AddRef() / Release() 管理对象生命周期。
角色概述
RefCounted 代表的是经典 intrusive reference counting 模式:
- 引用计数字段存放在对象内部
- 调用者手工执行
AddRef()/Release() - 计数归零时对象自己
delete this
这和 SmartPtr 里的 Ref<T> = std::shared_ptr<T> 是两套完全不同的所有权模型。当前代码里没有自动桥接它们,这一点非常重要。
当前实现行为
1. 初始引用计数是 1
构造函数会把 m_refCount 初始化为 1。tests/core/test_core.cpp 已验证这一点。
这意味着默认语义是:
new DerivedFromRefCounted()返回的对象立刻拥有一个初始引用- 你不需要在创建后先手工
AddRef()
2. Release() 在归零时直接 delete this
当前实现是:
if (--m_refCount == 0) {
delete this;
}
因此:
- 一旦
Release()让计数归零,对象就立即自删除 - 之后原来的裸指针立刻失效
这是 intrusive RC 最典型也最危险的一点。文档必须把它明确写出来。
3. 计数字段是原子变量
m_refCount 类型是 std::atomic<uint32_t>,所以单次增减操作具备基础原子性。
但这不等于“整个对象生命周期管理完全线程安全”。对象自己的其他状态并没有额外同步保护。
与 SmartPtr 的关系
当前项目里同时存在:
RefCountedRef<T>/UniqueRef<T>/MakeRef()/MakeUnique()
这很容易让人误以为 RefCounted 会自动和 Ref<T> 协同工作,但当前事实是:
Ref<T>只是std::shared_ptr<T>RefCounted只是手工 intrusive RC 基类- 两者当前没有自定义 deleter、适配器或统一 ownership 框架
所以使用时必须明确选一套模型,而不是混用后想当然。
使用边界
- 这种类型只适合堆分配对象。
- 不应把栈对象或外部所有权对象拿来调用
Release()。 - 如果对象已经由别的 RAII 所有权工具接管,再手工
Release()可能导致双重销毁。
测试覆盖
tests/core/test_core.cpp 已覆盖:
- 初始引用计数
AddRef()- 多次链式加减引用
Release()归零后自销毁路径
线程语义
- 引用计数增减是原子的。
- 对象其他成员状态没有自动同步。
- 释放最后一个引用的线程会执行
delete this。
当前实现限制
- 没有 weak reference 机制。
- 没有和
std::shared_ptr/Ref<T>的自动互操作。 - 只适合明确采用 intrusive RC 的对象模型。