Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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/