最近写工具的时候,句柄泄漏是最烦的一类 bug:函数中途 return,CloseHandle 就漏了。
用一个很小的 RAII 包装就能把生命周期绑到作用域上:struct Handle { HANDLE h; explicit Handle(HANDLE x = nullptr) : h(x) {} ~Handle() { if (h && h != INVALID_HANDLE_VALUE) CloseHandle(h); } Handle(const Handle&) = delete; Handle& operator=(const Handle&) = delete; HANDLE get() const { return h; }};
几点体会:
1. 构造失败不要把 INVALID_HANDLE_VALUE 和 nullptr 混成一种“空”。文件句柄失败返回的是 INVALID_HANDLE_VALUE,事件/线程失败才是 nullptr。
2. 不要写隐式 operator HANDLE()。隐式转换会让函数重载选错,调用方也看不出所有权已经交出去。
3. 如果要把句柄交给别人,单独写 release(),返回后把自己置空,避免析构再关一次。
4. 同一套写法可以套到 FindClose、RegCloseKey、LocalFree,不要每种 API 各写一份差不多的代码。
这种小包装不依赖第三方库,比到处 try/finally 手动关句柄好查。有人用 wil::unique_handle 或 std::unique_ptr 加自定义删除器,思路一样,看项目能不能引入额外头文件。 |