First let's format it so it's readable:
std::unique_ptr<std::remove_pointer<HANDLE>::type, void(*)(HANDLE)> hDevice{
h,
[](HANDLE handle) { CloseHandle(handle); }
};
This is a declaration of an object called hDevice
, initialised with two arguments. One is h
and the other is a lambda function. We'll come back to that.
The object's type is std::unique_ptr<std::remove_pointer<HANDLE>::type, void(*)(HANDLE)>
. The <>
mean that this is an instantiation of a template. The template in question is std::unique_ptr
, a standard component for memory management, a smart pointer.
Two things:
std::unique_ptr<T>
is a type of pointer to objects of type T
.
std::unique_ptr<T, D>
is a type of pointer to objects of type T
with custom "deleter" of type D
; we'll come back to that.
Your T
is std::remove_pointer<HANDLE>::type
. Windows gives us the type alias HANDLE
which is an obfuscated pointer type. This expression gives us the type of the thing that a HANDLE
points to (and does so in a nice generic way that doesn't have to hardcode the result; Microsoft could change the definition of HANDLE
and, as long as it is still a pointer, this'll still work).
Your D
is void(*)(HANDLE)
. That's the type of a function pointer, a pointer to a function taking HANDLE
and returning void
. Oh, that looks familiar: it's a function pointer type compatible with the lambda you gave as the constructor parameter.
That's because the lambda is the custom deleter. It tells the unique_ptr
what to do when the smart pointer goes out of scope. Usually that'd just be a nice delete
, but here we have a Windows API function (CloseHandle
) to call instead, which does the cleanup for us. This may involve a delete
and other things, or it may involve just other things. Point is this is the proper way to close a HANDLE
.
Overall, what's going on is that this declaration creates a std::unique_ptr
that takes ownership of a HANDLE h
, and ensures that CloseHandle(h)
is invoked when the std::unique_ptr
goes out of scope.
tl;dr: It's a way to add RAII to a Windows handle.