采用Map管理资源句柄并配合引用计数可实现轻量级局部资源管理,关键在于增删查操作与资源生命周期严格同步:Map存句柄而非裸指针,插入先AddRef再写入,删除先Release再erase,查找后需显式AddRef,释放由计数归零驱动,非Map控制。

直接用 Map 管理资源句柄并配合引用计数,是实现轻量级局部资源管理器的常见做法。关键不在 Map 本身,而在如何让 Map 的增删查操作与资源生命周期严格同步——避免对象被提前释放,也防止内存长期驻留。
Map 存句柄,不存裸指针
Map 的 value 类型应为资源句柄(如 texture::handle 或自定义的智能句柄),而非原始指针。句柄内部封装了对引用计数的访问能力,确保每次通过 Map 获取资源时,都能安全触发 AddRef();释放时调用 Release(),而非直接 delete。
- 例如:声明
std::map<:string texture::handle> m_TextureCache;</:string> - 插入时:
m_TextureCache[name] = loadTexture(name);—— 此时句柄构造或赋值会自动完成AddRef() - 查找后使用前,显式调用
handle->AddRef()(若句柄未自动保活)
增删操作必须原子绑定计数变更
Map 自身不提供线程安全,更不保护其 value 所指向的对象。因此 insert/erase 操作必须和引用计数联动,且需加锁(或用无锁结构)保证逻辑完整性:
-
insert 时:先调用资源的
AddRef(),再写入 Map;否则可能刚写入、还没来得及增加计数,就被其他线程 erase 并释放 -
erase 时:先从 Map 取出句柄,再调用其
Release(),最后执行map.erase() -
find 后使用:查到句柄后立即
AddRef(),使用完再Release();这一步不能省略,因为 Map 中的句柄只是“弱引用”快照
资源释放由计数驱动,非 Map 驱动
Map 只负责索引与暂存,真正的释放时机永远由引用计数归零决定。这意味着:
- 即使某个资源仍在 Map 中,只要所有外部持有者都调用了
Release(),且计数降为 0,资源就会被自动销毁 - Map 中残留的句柄在下次访问时会失效(句柄可设计为 null-check 或 throw 异常),不会导致悬垂访问
- 定期清理 Map 中已失效的句柄(如遍历 +
handle->GetRefCount() == 0判断)可减少冗余条目,但非必需
避免常见陷阱
几个高频出错点需要特别注意:
- 不要在 Map 锁外做
AddRef()或Release()—— 容易因竞态导致计数错乱或 double-free - 不要把
shared_ptr直接塞进 Map 当 value —— 若多个模块共享同一shared_ptr实例,Map 的拷贝会干扰原有生命周期 - Map 的 key 应具备稳定性(如字符串名、哈希 ID),避免用临时对象地址或易变字段作 key
- 调试时可通过
GetRefCount()打印日志,确认增减是否成对、有无遗漏

















