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 s
inspired by Alexander Drichel's solution, here is even shorter
std::unique_ptr< HANDLE, decltype(&CloseHandle) > 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.
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);
A HANDLE does not always close with CloseHandle(), beware. For example a HANDLE opened with FindNextFile() must be closed by FindClose().
Here is a handy little "custom_ptr" I use for dealing with a HANDLE.
C++17 is required in order for this to compile. This idea was lifted from another SO post, I only added the std::remove_pointer_t<T> so that I wouldn't have to pass void as the custom_ptr type parameter.
Definition
#include <type_traits>
#include <memory>
template<auto fn>
using deleter_from_fn = std::integral_constant<decltype( fn ), fn>;
template<typename T, auto fn>
using custom_ptr = std::unique_ptr<typename std::remove_pointer_t<T>, deleter_from_fn<fn>>;
Use
custom_ptr<HANDLE, &CloseHandle> phandle{
CreateFileMapping( INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1024, L"FileName" ) };
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<typename T> void operator()(T* ptr) {
ptr->Release();
}
};
unique_ptr<IUnknown, COMDeleter> ptr; // Works fine
The same principle applies to shared_ptr and indeed, to HANDLE.
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.