7

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.

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Paul
  • 25,812
  • 38
  • 124
  • 247
  • 6
    that's a [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr) with a custom deleter. Ref. eg. : [How do I use a custom deleter with a std::unique_ptr member?](https://stackoverflow.com/questions/19053351/how-do-i-use-a-custom-deleter-with-a-stdunique-ptr-member) – Sander De Dycker Jul 30 '19 at 13:24
  • 1
    Possible duplicate of [How do I use a custom deleter with a std::unique\_ptr member?](https://stackoverflow.com/questions/19053351/how-do-i-use-a-custom-deleter-with-a-stdunique-ptr-member) – ruohola Jul 30 '19 at 13:25
  • 6
    `a "bigger than" symbol` so you aren't even familiar with templates? – KamilCuk Jul 30 '19 at 13:28
  • @Lightness Races in Orbit: I am trying to convert it to Delphi because accordingly to description the function does what I need. – Paul Jul 30 '19 at 13:30
  • 6
    Research terms: class template, type trait, function pointer, lambda expression. Honestly though, it sounds like you could use a [good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – NathanOliver Jul 30 '19 at 13:31
  • 5
    I recommend writing code from scratch rather than translating between unrelated languages. Even if you succeed the wrong idioms will be applied – Lightness Races in Orbit Jul 30 '19 at 13:38
  • Also see: [std::unique_ptr, deleters and the Win32 API](https://stackoverflow.com/questions/14841396/) – Remy Lebeau Jul 30 '19 at 21:00
  • 1
    @KamilCuk "*so you aren't even familiar with templates?*" - Delphi has [Generics](http://docwiki.embarcadero.com/RADStudio/Rio/en/Generics_Index), which are similar to C++ templates, and also use angle brackets when declaring and instantiating Generic types. – Remy Lebeau Jul 30 '19 at 21:02

1 Answers1

18

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.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055