使用带自定义删除器的unique_ptr调用GetModuleHandleEx及HMODULE释放问题
HMODULE是否需要释放?
首先明确:是否需要释放HMODULE取决于调用GetModuleHandleExW时使用的标志:
- 若调用时未指定
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,系统会自动增加模块的引用计数,此时必须调用FreeLibrary释放HMODULE,否则会造成模块引用计数泄漏,导致模块无法正常卸载。 - 你的代码中使用了
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,该标志仅用于通过地址定位模块,不会改变引用计数的默认行为——系统仍会给模块的引用计数+1,因此你必须释放这个HMODULE。
另外补充:你现有代码中的FreeResource调用是冗余的,LoadResource返回的HGLOBAL无需手动释放,系统会在模块卸载时自动清理,强行调用反而可能引发问题。
带自定义删除器的
unique_ptr正确用法 你定义的删除器是正确的,但使用方式有误——unique_ptr::get()返回的是内部指针的副本,无法直接取地址传给GetModuleHandleExW(因为get()返回的是右值,且unique_ptr的内部指针不能通过这种方式修改)。以下是两种正确的实现方式:
方法一:临时存储HMODULE后转移给unique_ptr(推荐)
struct Deleter { void operator()(HMODULE hModule) const { if (hModule != nullptr) { FreeLibrary(hModule); } } }; using unique_module = std::unique_ptr<std::remove_pointer<HMODULE>::type, Deleter>; // 使用示例 DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS; HMODULE hm = nullptr; if (::GetModuleHandleExW(flags, L"Test.dll", &hm)) { unique_module um(hm); // 将获取到的HMODULE转移给unique_ptr,后续自动释放 // 通过um.get()访问HMODULE HRSRC hResource = ::FindResourceW(um.get(), MAKEINTRESOURCEW(TEST1), L"ICON"); // ... 后续资源操作代码 } else { // 错误处理 }
方法二:直接修改unique_ptr内部指针(可读性较差)
若想让GetModuleHandleExW直接写入unique_ptr的内部指针,可通过&*um获取内部指针的引用地址(前提是unique_ptr初始化为nullptr):
unique_module um(nullptr); if (::GetModuleHandleExW(flags, L"Test.dll", &*um)) { // 通过um.get()操作模块 }
额外优化方案
如果你的场景只是临时获取模块句柄读取资源,不需要保留模块引用,可以在调用GetModuleHandleExW时添加GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT标志,此时系统不会增加模块引用计数,无需调用FreeLibrary释放HMODULE,也就不需要使用带删除器的unique_ptr:
DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; HMODULE hm = nullptr; if (::GetModuleHandleExW(flags, L"Test.dll", &hm)) { // 使用hm读取资源,无需释放 }
内容的提问来源于stack exchange,提问作者Vk0726
相关产品推荐
相关产品推荐

