STL functors, scoped handles and how we can use them in Windows programming
Firstly, it's election day so get out there and vote! Secondly, I went to bed last night and dreamt about functors! Last Friday I code-reviewed some changes made by one of my colleagues and his code just happened to use some STL containers and all sorts of related goodies. The last time I tried to use STL was about eight years ago when I was still at college and, admittedly, I didn't use them much: compiler support (both on Unix and Windows platforms) was not great and so I ended up using Matlab for most of my work instead.
Anyway, this got me thinking: wouldn't it be nice to be able to use the STL auto_ptr
template to manage Windows handles in addition to regular old object pointers? Unfortunately, this was a no-go for two main reasons:
- The semantics are all wrong:
auto_ptr<HANDLE>
, whereHANDLE
is a generic Windows-style opaque pointer, doesn't work as the resultingauto_ptr
specialization is semantically equivalent toHANDLE *
(i.e. a pointer to aHANDLE
). This is one level of pointer indirection too much to be useful for us. auto_ptr
, unlike the TR1shared_ptr
, does not allow the developer to define a custom deleter function:auto_ptr
always invokes thedelete
operator on the type of the encapsulated pointer. Windows handles typically useCloseHandle
or something similar.
So, I began to write my own. First, I thought I'd steal some inspiration from the auto_ptr
and shared_ptr
classes. Unfortunately, this is not easy as it might sound. Anybody who has ever read the source code for STL would likely agree with me on this: the STL headers are not designed to be humanly readable as far as I can tell. Therefore I had to write it from scratch and reproduced below is my scoped_handle
implementation:
Click to view source code for scoped_handle
Of course, I went through several iterations before I got it right. The first used a single encapsulated deleter function pointer. This suffered from the main issue that the deleter function had to conform to a very specific function prototype. Thus it becomes difficult to produce a generic class that can handle void (*)(HANDLE)
functions and BOOL (*)(HANDLE)
equally well (CloseHandle
belonging to the latter category). After some head scratching I developed the implementation listed above based on the STL-style concept of functors. Specifically, this template class can handle any object, be it a function or class or anything else, as long as it supplies an overload of operator()
that takes a single appropriately typed argument. This operator can return any type since scoped_handler
ignores the return value anyway.
A few caveats become obvious:
- Beware compiler warning C4930 from Visual C++! This warning is the reason why I did not provide a constructor of the form
explicit scoped_handle(CALLABLE_TYPE)
which would have created a default, "empty" handle set toUNDEFINED_VALUE
initialized with the specified deleter. The compiler cannot distinguish between a class instantation or function prototype in this type of code. - This code throws C++-style exceptions. If you're using this class in COM code you must catch all C++ exceptions and translate them into equivalent
HRESULT
s or stack-unwinding chaos will ensue.
This is roughly how one might use the scoped_handle
class in conjunction with common Windows APIs:
Click to view source code for example of usage
See you next time!
Comments
- Anonymous
November 04, 2008
PingBack from http://blog.a-foton.ru/index.php/2008/11/04/stl-functors-scoped-handles-and-how-we-can-use-them-in-windows-programming/