正确关闭WinAPI句柄(避免重复关闭) [英] Proper way close WinAPI HANDLEs (avoiding of repeated closing)
问题描述
我有一些手柄,需要关闭它.在代码中的某些位置,可能会关闭句柄.那么,这是关闭手柄的正确方法吗?
I have some handle and I need to close it. There is some places in code, where handle may be closed. So, is this a right way to close handle?
HANDLE h;
....
if ( h != INVALID_HANDLE_VALUE ) {
::CloseHandle(h);
h = INVALID_HANDLE_VALUE;
}
关于位图句柄有一个相同的问题:
There is a same question about bitmap handles:
HBITMAP hb;
....
if ( hb != INVALID_HANDLE_VALUE ) {
::DeleteObject(hb);
hb = INVALID_HANDLE_VALUE;
}
我认为,存在一些误解.我知道CloseHandle
用于关闭句柄.我想知道关闭手柄的正确方法.删除指针也会发生类似情况.
I think, there is some misunderstanding. I know CloseHandle
is for closing handles. I'd like to know proper way for closing handles. A similar situations occurs with deleting of pointers.
Foo *foo = new Foo();
// for example there is 2 functions that can delete foo
void bar() {
....
delete foo;
}
void duck() {
....
delete foo;
}
因此,以下代码表示问题:
So, the following code means problems:
bar();
duck();
在这种情况下,有一些解决方法.我们需要这样定义bar
& duck
函数:
There is some workaround for this case. We need to define bar
&duck
functions like this:
void bar() {
....
if (foo) {
delete foo;
foo = NULL;
}
}
void duck() {
....
if (foo) {
delete foo;
foo = NULL;
}
}
因此,我们避免重复删除foo.问题是关闭手柄的正确方法是什么?我的意思是,如何避免重复关闭手柄的问题?
So we avoid repeated deleting of foo. The question is What is the proper way to close handles? I mean, How to avoid repeated closing handles problem?
推荐答案
并非所有使用HANDLE
的函数都使用CloseHandle()
,有些则使用其他关闭函数.同样,也不是所有的HANDLE
值都使用INVALID_HANDLE_VALUE
.有些人使用NULL
代替.
Not all functions that use HANDLE
use CloseHandle()
, some use other closing functions instead. Also, not all HANDLE
values use INVALID_HANDLE_VALUE
, either. Some use NULL
instead.
HBITMAP
从不使用INVALID_HANDLE_VALUE
,而始终使用NULL
.而且,您永远不要为自己不拥有的HBITMAP
呼叫DeleteObject()
.
HBITMAP
never uses INVALID_HANDLE_VALUE
, it always uses NULL
. And you should never call DeleteObject()
for an HBITMAP
you do not own.
因此,简短的答案是-如果您尝试创建一些通用的句柄管理,请不要打扰.您可能会弄错.如果分配/打开某个句柄,则必须知道关闭它的正确方法,无法猜测.
So the short answer is - if you are trying to create some general purpose handle management, don't bother. You are likely to get it wrong. If you allocate/open some handle, you have to know the correct way to close it, you can't guess at it.
如果您希望句柄自行管理,那么RAII是最佳选择.我更喜欢使用具有特殊特征的模板化类来减少不同类型的句柄的代码重复,例如:
If you want the handles to manage themselves, then RAII is the best choice. I prefer to use a templated class with specialized traits to reduce code duplication for differrent types of handles, eg:
template< class traits >
class HandleWrapper
{
private:
traits::HandleType FHandle;
public:
HandleWrapper()
FHandle(traits::InvalidValue)
{
}
HandleWrapper(const traits::HandleType value)
FHandle(value)
{
}
~HandleWrapper()
{
Close();
}
void Close()
{
if (FHandle != traits::InvalidValue)
{
traits::Close(FHandle);
FHandle = traits::InvalidValue;
}
}
bool operator !() const {
return (FHandle == traits:::InvalidValue);
}
operator bool() const {
return (FHandle != traits:::InvalidValue);
}
operator traits::HandleType() {
return FHandle;
}
};
.
struct KernelHandleTraits
{
typedef HANDLE HandleType;
static const HANDLE InvalidValue = INVALID_HANDLE_VALUE;
static void Close(HANDLE value)
{
CloseHandle(value);
}
};
HandleWrapper<KernelHandleTraits> hFile(CreateFile(...));
.
struct NullKernelHandleTraits
{
typedef HANDLE HandleType;
static const HANDLE InvalidValue = NULL;
static void Close(HANDLE value)
{
CloseHandle(value);
}
};
HandleWrapper<NullKernelHandleTraits> hMapping(CreateFileMapping(...));
.
struct FileMapViewTraits
{
typedef void* HandleType;
static const void* InvalidValue = NULL;
static void Close(void *value)
{
UnmapViewOfFile(value);
}
};
HandleWrapper<FileMapViewTraits> hView(MapViewOfFile(...));
.
struct GDIBitmapHandleTraits
{
typedef HBITMAP HandleType;
static const HBITMAP InvalidValue = NULL;
static void Close(HBITMAP value)
{
DeleteObject(value);
}
};
HandleWrapper<GDIBitmapTraits> hBmp(CreateBitmap(...));
等等.
这篇关于正确关闭WinAPI句柄(避免重复关闭)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!