昨天在公司进行 Code Review 时同事有类似如下一段代码:
if (pi.hThread != NULL) { CloseHandle(pi.hThread); } if (pi.hProcess != NULL) { CloseHandle(pi.hProcess); }
,这段代码位于函数的收尾处,所以没有通常能见到的关闭句柄后置NULL操作。这不是我的疑问,我的疑问是,“判断句柄非空”的意义是什么?当时那位同事没能很好地回答这个问题,虽然大家都经常这么做。CloseHandle(NULL); 会发生什么事?大家觉得什么都不会发生,相安无事。
MSDN上对 CloseHandle 的说明是:
BOOL WINAPI CloseHandle( _In_ HANDLE hObject ); Closes an open object handle. hObject [in] A valid handle to an open object. 关闭一个已经打开的对象句柄,一个有效的对象句柄。
NULL(0)是一个有效的对象句柄吗?肯定不是。
那 INVALID_HANDLE_VALUE(-1) 呢?这是另外一个代表句柄无效的值。 CloseHandle(INVALID_HANDLE_VALUE); 会发生什么事呢?实际上,当程序在正常运行状态时,跟 NULL 一样,啥也不会发生。
那这是不是意味着,我们无需检测 CloseHandle 参数的句柄值是 NULL 或 INVALID_HANDLE_VALUE 就可以直接传递过去呢?实际上这样行不通,如果仔细读 MSDN 的话,它这样说道:
If the application is running under a debugger, the function will throw an exception if it receives either a handle value that is not valid or a pseudo-handle value.
“在应用程序在被调试状态时,一个无效的句柄值或伪句柄值将使 CloseHandle 抛出一个异常。” 啥是伪句柄? GetCurrentProcess() 的返回值 INVALID_HANDLE_VALUE(-1) 就是一个伪句柄。
所以,根据经验:仅仅调用 CloseHandle 来关闭那些你成功打开的句柄,并且对每个句柄仅关闭一次。
所以,那位同事的做法可能需要一些改进才能使程序更加健全。