Here's an article that talks about an idiom named Rule of Zero.
Here's an excerpt:
class module {
public:
explicit module(std::wstring const& name)
: handle { ::LoadLibrary(name.c_str()), &::FreeLibrary } {}
// other module related functions go here
private:
using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;
module_handle handle;
};
It reuses unique_ptr
RAII features so you don't need to care about implementing a daunting and verbose Rule of Five wrapper.
Presented this way (managing handle based resources with unique_ptr
, that way), it looks as a hack for me, not a best solution for what it's trying to solve. Too many assumptions are being implicitly assumed:
- One is able to peer and use the basic type the
#define
(ortypedef
)HANDLE
is built upon. For me this should be hidden knowledge, and a solution be based exclusively on what the interface makes available:HANDLE
. - Handles, can be anything, they're not required to be pointer types.
I'd like to use this idiom, but it falls short in many situations I stumble upon.
Is this handle focused RAII wrapper already done and usable in some cool library? Is everybody using such a tool and I'm not aware? (I think it nice to have such tooling not only for one, but for the many types of ownerships that are)
EDIT 1
This is not about platform specific resource handles, e.g., glGenLists
returns a kind of handle, it's a GLuint
, and you should call glDeleteLists
on it. As already stated, resource handles are not required to be pointer types, and this assumption should not be assumed.
EDIT 2
Rule of Zero, in the former sample, by employing an already existing tool, unique_ptr
, shows as a nice shortcut for handle management. The extra assumptions that it requires makes it falls short. The right assumptions are that you have a handle and you have a resource destroying function that destroys the resource given by the handle. Whether the handle is a void *
, a GLuint
, whatever, it should not matter, and worse, one should not even be required to peer HANDLE
inner type. For the purpose of managing handles RAII way, if the idiom tells it's good for that, and can't apply in such situations, I feel it's not good for that, at last with the given tool.
EDIT 3
An illustrative situation would be, let's say you're in charge of using a fresh 3rd party C library. It contains a FooHandle create_foo()
and a void destroy_foo(FooHandle)
. So you think, "let's use FooHandle's by employing the Rule of Zero". Ok, you go by using a unique_ptr
, a unique_ptr
to what you ask yourself? Is FooHandle
a pointer?, so that you use a unique_ptr
to FooHandle
's not exposed basic type? Is it an int
?, so that you may use it straight, or is it better to (re)typedef
things like @NicolBolas has done in his answer. For me, it seems clear, even in such a trivial situation, unique_ptr
is already showing as not an ideal fit for managing resource handles.
Disclaimer:
I've tried to reformulate and better express myself in:
EDIT 4
I've found what I was looking for, I've put it as an answer in the reformulated question: https://stackoverflow.com/a/14902921.
HANDLE
in the winapi is avoid *
. That will never change, and is clearly stated in theWindows Data Types
article. I see absolutely no problem with using a smart pointer to easily employ RAII. – Coercionunique_ptr
like that, and make one think c++ is already good at such a kind of tool, so you may just employ them instead of writing one yourself. – Keslerunique_ptr
, ifFooHandle
is a pointer type, theunique_ptr
should be constructed upon the basic type (like the excerpt has badly done) not straight fromFooHandle
alone. What if it turns out to be just an int? The semantics of handles are just like this,unique_ptr
doesn't fit, it's a hack. – Kesler