可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I was wondering if there is a way to use unique_ptr
with Windows HANDLEs?
I was thinking to replace the std::default_delete
with specific handle_trats
that calls CloseHandle
. The problem is that HANDLE
is defined as void*
unique_ptr
won't compile as sizeof(void)
is not defined.
So far I see only two possibilities:
- Create a wrapper class for HANDLEs and use it like this:
unique_ptr
. This pretty much makes the unique_ptr
itself useless. - Use
HANDLE
specific smart pointer class that resembles unique_ptr
.
What do you think is better choice? What would you suggest?
The question can be extended for COM IUnknown
pointers - can CComPtr
be replaced by any of the standard smart pointers?
回答1:
The question can be extended for COM IUnknown pointers - can CComPtr be replaced by any of the standard smart pointers?
Yes. You don't specialize std::default_deleter
, you simply replace the deleter type.
struct COMDeleter { template void operator()(T* ptr) { ptr->Release(); } }; unique_ptr ptr; // Works fine
The same principle applies to shared_ptr
and indeed, to HANDLE
.
回答2:
Create a specific smart pointer class, won't take long. Don't abuse library classes. Handle semantics is quite different from that of a C++ pointer; for one thing, dereferencing a HANDLE makes no sense.
One more reason to use a custom smart handle class - NULL does not always mean an empty handle. Sometimes it's INVALID_HANDLE_VALUE, which is not the same (actually -1).
回答3:
You can typedef your unique_ptr
with a custom deleter
struct handle_deleter { void operator()(void* handle) { if(handle != nullptr) CloseHandle(handle); } }; typedef std::unique_ptr UniqueHandle_t; UniqueHandle_t ptr(CreateFile(...));
回答4:
You can create a Deleter class that will release the handle instead of calling delete().
You can see in this LINK how they've solved deleting arrays with a shared_ptr (unique_ptr also has a constructor that recieves a Delete class)
struct handle_deleter { void operator ()( HANDLE handle) { CloseHandle(p); } }; HANDLE blah = GetSomeHandle(); unique_ptr myPointer(blah,handle_deleter);
回答5:
I don't recommend using smart pointers with handles.
I recommend you to take a look at A Proposal to Add additional RAII Wrappers to the Standard Library and at the drawbacks of using smart pointers with handles.
Personally, I'm making use of the reference implementation of that proposal instead of using std::unique_ptr
for these situations.
回答6:
yet another solution
std::unique_ptr uniqueHandle( file, []( HANDLE h ) { ::CloseHandle( h ); } );
回答7:
inspired by Alexander Drichel's solution, here is even shorter
std::unique_ptr uniqueHandle( nullptr, CloseHandle );
Works in MSVC 2010. Note that you need to specify '&' for the function name in decltype() to deduce a pointer-to-function type.
回答8:
A HANDLE does not always close with CloseHandle(), beware. For example a HANDLE opened with FindNextFile() must be closed by FindClose().
回答9:
You must use CloseHandle()
to "close" a handle instead using delete
. They will be deleted by Windows as soon as they are not opened elsewhere. So you could write a wrapper that calls CloseHandle() instead of deleteing it. You could also write your own smartpointer class which might be better as there is no need of a wrapper anymore.