Handles have proper semantics other than pointers. So for me an example like this (extracted from the Rule of Zero):
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;
};
using unique_ptr
as an 'ownership-in-a-package' for handles is a bad example. First, it makes use of internal knowledge that the handle is a pointer type, and use this to make a unique_ptr
to the basic type the "opaque" handle type builds upon.
Handles can be any type, they may be a pointer, they may be an index or who knows. Most importantly, what you have at hand (from most C API's for example) is a handle and its resource releasing function.
Is there a proper 'ownership-in-a-package' that works in handle semantics? I mean, already publicly available for one to use?
For me, unique_ptr
et. al. doesn't work, I must make unnecessary assumptions about what the handle type is, when what I want is just to get an 'ownership-in-a-package' through the opaque handle type and its releasing function, solely.
It doesn't make sense for one to peer inside the handle type to make constructions upon this information. It's a handle, it should not matter.
I'll quote here the feelings of another SO user in another question's answer:
Create a specific "smart pointer" class, won't take long. Don't abuse library classes. Handle semantics is quite different from that of a C++ pointer; for one thing, dereferencing a HANDLE makes no sense.
One more reason to use a custom smart handle class - NULL does not always mean an empty handle. Sometimes it's INVALID_HANDLE_VALUE, which is not the same.
Disclaimer:
This question reformulates and builds upon this one:
unique_ptr
is maybe a slight misnomer – it handles resources. AHANDLE
also handles resources. This is a perfect match. – Stutterunique_ptr
? – LatT*
at construction. – Bullateunique_ptr
for a non-pointer handle, you need to a special deleter which defines a nestedpointer
type, and thatpointer
type can't simply be, say,int
, sinceint
doesn't conform to the NullablePointer requirements thatunique_ptr
wants. However, you can write a simple wrapper that adapts anything to those nullable pointer requirements. If you fancy, you can also add a unaryoperator*
that forwards to*value
, and anoperator->
so you can actually use*up
andup->foo()
. – Danielsontemplate
wrapping aroundunique_ptr
. – Gardeningunique_ptr
for non-pointer things. Seriously, writing copy/move constructors for one object is hardly an onerous burden. – Reich