I found on Github a function with a pretty weird one-liner inside:
std::unique_ptr<std::remove_pointer<HANDLE>::type, void(*)(HANDLE)> hDevice{h, [](HANDLE handle){CloseHandle(handle);}};
As a person who never dealt with c++ I have no idea what it does.
I suppose, here are two nested anonymous functions connected somehow with std::remove_pointer
and std::unique_ptr
calls. I see an WinAPI CloseHandle
call in the inner function and suppose that I should start my analysis with it. I cannot say more.
May be here are two nested generics.
The use of curly braces and a "bigger than" symbol also seems pretty strange to me. It breaks all the canonical cases I know.
Please help to understand this conglomerate. I do not know how to google its parts.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With