资源句柄必须用 std::shared_ptr 封装并配自定义删除器调用卸载api,缓存需用 std::weak_ptr 防止内存泄漏,gpu资源卸载须延迟至帧结束且避免 shared_ptr 延长生命周期,管理器禁用 std::enable_shared_from_this 防循环引用。

资源句柄必须用 std::shared_ptr 封装,不能裸指针
裸指针无法触发自动释放逻辑,引用计数机制就彻底失效。所有对外暴露的资源句柄(比如纹理、模型、音频)都得是 std::shared_ptr 类型,内部指向一个统一的资源包装类(如 ResourceWrapper),该类持有原始资源指针和卸载函数。
常见错误是:把 std::shared_ptr<resource></resource> 直接返回给用户,但 Resource 析构时没调用卸载逻辑——这会导致资源泄漏。正确做法是让 std::shared_ptr 的自定义删除器(deleter)负责调用 unload() 或 OpenGL/Vulkan 的销毁 API。
- 删除器必须捕获资源 ID 或句柄(如
GLuint、vkBuffer),不能只依赖对象成员变量(对象可能已析构) - 避免在删除器里抛异常——
std::shared_ptr的析构不保证异常安全 - 如果资源加载失败,返回空
std::shared_ptr,不要返回nullptr强转
资源加载器需维护全局弱引用缓存:std::weak_ptr + std::unordered_map
重复加载同一路径的资源(如多次请求 "assets/hero.png")必须复用已有实例,否则内存爆炸。缓存键用文件路径或哈希值,值存 std::weak_ptr,每次取之前先 lock() 检查是否还存活。
注意:不能用 std::shared_ptr 直接存进缓存,否则即使外部无引用,缓存本身也会阻止资源释放。必须用 std::weak_ptr,靠 lock() 瞬时升级为强引用。
- 缓存 key 建议用
std::string_view或 SHA-1 哈希,避免路径字符串频繁拷贝 - 缓存无锁访问可考虑
std::shared_mutex(C++17),读多写少场景下比std::mutex更轻量 - 加载失败时,缓存中对应项要显式擦除(否则
weak_ptr::lock()返回空,但键仍占内存)
卸载时机取决于资源类型:GPU 资源必须在渲染帧结束之后
像 OpenGL 纹理、Vulkan buffer 这类 GPU 资源,不能在任意时刻调用 glDeleteTextures 或 vkDestroyBuffer —— 如果当前帧还在用,驱动可能崩溃或静默失败。必须延迟到下一帧开始前、所有命令提交完毕后执行。
典型做法是维护一个“待卸载队列”,每帧末尾遍历并执行。这个队列里存的不是资源本身,而是卸载函数对象(std::function<void></void>)或结构体(含 ID + 函数指针)。
- 不能把
std::shared_ptr存入延迟队列——它会延长生命周期,导致本该卸载的资源卡住不释放 - Vulkan 用户尤其要注意:
vkDestroy*必须在对应资源不再被任何vkQueueSubmit引用后调用,通常配合vkDeviceWaitIdle或 fence 同步 - 音频、脚本等 CPU 资源可立即卸载,不必延迟;混用时建议统一走延迟队列,逻辑更一致
std::enable_shared_from_this 不适合资源管理器自身
资源管理器(如 ResourceManager 单例)若继承 std::enable_shared_from_this,容易引发循环引用:管理器持有着资源的 shared_ptr,而资源又通过回调或观察者模式持有了管理器的 shared_ptr —— 结果谁也释放不了。
真正需要的是“管理器不参与引用计数”。要么用原始指针(确保管理器生命周期长于所有资源),要么用 std::weak_ptr 配合 lock() 安全访问,或者干脆设计成无状态函数式接口(如静态 load_texture())。
- 资源类内部若需回调管理器,一律用
std::weak_ptr<resourcemanager></resourcemanager>,调用前lock() - 避免在资源构造函数里直接调用管理器方法(此时管理器可能还没完全初始化)
- 如果管理器必须被资源持有,且生命周期可控,可用
std::unique_ptr+ 自定义释放策略,而非共享所有权
最易被忽略的一点:引用计数只管“有多少人在用”,不管“能不能用”。GPU 资源被显存不足强制回收、音频设备断开、文件被外部修改——这些情况不会触发 shared_ptr 的析构,得靠额外的状态检查和重载机制来兜底。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











