RAII resource wrapper details - microsoft/wil GitHub Wiki
This page documents the details of the WIL resource management classes (resource.h), for those who need to integrate with or debug those classes.
- ownership
The obligation to close or otherwise dispose of another object.
- empty
The state of a resource type when it does not own anything.
The wil::details::resource_policy traits class decribes how an object
is managed by the wil library's unique_* classes.
Use this value if you are defining a new resource type and you need
finer control than unique_any_t provides.
template <typename pointer,
typename close_fn_t,
close_fn_t close_fn,
typename pointer_access = wil::details::pointer_access_all,
typename pointer_storage = pointer,
pointer invalid = pointer(),
typename pointer_invalid = wistd::nullptr_t>
struct resource_policy;Template parameters
-
pointer
The underlying data type that is managed by theunique_*wrapper. For types wrapped byunique_ptr, it is typically a pointer type.
-
close_fn_t
The type of the function that is used to close the underlying resource.- The
close_fn_tandclose_fnare usually passed as the pairdecltype(something), something.
- The
-
close_fn
A unary operation (typically a function) which closes the underlying resource.- It is called with one parameter, a
pointer_storagecontaining the resource to be closed. - It will not be called with the
invalidvalue.
- It is called with one parameter, a
-
pointer_access(default ispointer_access_all)
A pointer access value (see below) which controls visibility of the underlying pointer to clients.
-
pointer_storage(default ispointer)
The type used to store the underlying data type. This is usually the same aspointer, but will be different if the underlying storage is itself a wrapper class, such as a smart pointer. Thepointer_storagemust have an implicit conversion topointerand vice versa.
-
invalid(default is null/zero value ofpointer)
The value which represents that there is no resource. Defaults to the null/zero value of thepointertype.
-
pointer_invalid(default iswistd::nullptr_t)
The typewistd::nullptr_tif you are allowed toresetor assignnullptrto theunique_*wrapper. If the underlying data type is not a pointer type, then passpointerinstead.
Member types
-
pointer_storage
Thepointer_storagetype specified in the template.
-
pointer
Thepointertype specified in the template.
-
pointer_access
Thepointer_accessvalue specified in the template.
-
pointer_invalid
Thepointer_invalidtype specified in the template.
Methods
-
static pointer_storage invalid_value()
Produces theinvalidvalue.
-
static bool is_valid(pointer_storage value)
Reports whether the value is theinvalidvalue.
-
static void close(pointer_storage value)
Closes the resource represented byvalue, which will never beinvalid.
-
static void close_reset(pointer_storage value)
Closes the resource represented byvalue, which will never beinvalid, while preserving theGetLastErrorvalue.
The wil::details::pointer_access_* values control how much access the
client of a unique_* wrapper has to the wrapped pointer value.
Use this value if you are defining a new resource type and wish to restrict access to the raw pointer.
| Value | Can move | Can get()
|
Can release()
|
Can addressof() and &
|
|---|---|---|---|---|
wil::details::pointer_access_all |
Yes | Yes | Yes | Yes |
wil::details::pointer_access_noaddress |
Yes | Yes | Yes | No |
wil::details::pointer_access_none |
Yes | No | No | No |
The wil::details::unique_storage template class is a low-level smart
pointer class which provides the underlying storage and memory
management operations for the unique_* wrappers. The unique_storage
is an RAII class which manages the lifetime of another object (the
owned object). If the unique_storage is not managing any object, it
is said to be empty.
A unique_storage is the size of a pointer_storage, which is
typically a pointer.
You usually do not need to use this class directly.
It is separate from unique_any_t to allow a type-specific
specialization class to insert itself into the inheritance chain between
unique_any_t and unique_storage. Classes like unique_event take
advantage of this so that they can be a unique_any, but with
additional methods like SetEvent.
template <typename policy>
struct unique_storage;Template parameters
-
policy
Theresource_policythat describes the behavior of the resource.
Member types
-
policy(protected)
Theresource_policytype specified in the template.
-
pointer_storage(protected)
Thepointer_storagetype of the policy.
-
pointer(protected)
Thepointertype of the policy.
-
base_storage(protected)
Theunique_storageclass itself.
Constructors
-
unique_storage()(protected)
Initializes an empty storage. -
unique_storage(pointer_storage ptr)(protected)
Takes ownership of the provided pointer.
Methods
-
pointer get() const
Returns a pointer to the object being managed, or a policy-defined invalid value (usually a null pointer) if theunique_storageis empty.
-
void reset(pointer_storage ptr)
Closes the pointer currently being managed and takes ownership of the new pointer.
-
void reset()
Closes the pointer currently being managed and leaves the object empty.
-
void reset(nullptr)
Closes the pointer currently being managed and leaves the object empty. Allowed only if the underlying type is a pointer. (Thepolicy::pointer_invalidmust bewistd::nullptr_t.)
-
pointer_storage release()
Makes theunique_storageempty and returns the object that was previously being managed. It is the caller's responsibility to close the returned object. (The pointer access policy must be all or noaddress.)
-
pointer_storage* addressof()
Returns a pointer to the internal pointer storage. (The pointer access policy must be all.)
-
void replace(unique_storage&& other)(protected)
Closes the pointer currently being managed and takes ownership of the pointer managed by theotherobject.
-
bool is_valid() const(protected)
Returnstrueif an object is being managed, or orfalseif theunique_storageis empty.
Note that the release method behaves differently from the
same-named method of COM and MFC wrapper classes. The behavior of the
unique_storage aligns with the C++
standard.
unique_storage |
COM/MFC wrappers | Description |
|---|---|---|
reset |
Attach |
Take ownership of a raw pointer. |
release |
Detach |
Return a raw pointer and transfer the ownership to the caller. |
As noted above, you can derive from unique_storage in order to inject
methods into the underlying type. For example, consider a platform type
HWIDGET. You could start with a unique_any
declaration:
using unique_widget = unique_any<HWIDGET, decltype(::CloseWidget), ::CloseWidget>;Operations on widgets would go like this:
unique_widget widget{ CreateWidget() };
WiggleWidget(widget.get());If you desire to make wiggling a widget more convenient, you could
inject the wiggle method into the unique_widget as follows:
class widget_t :
public wil::details::unique_storage<
wil::details::resource_policy<HWIDGET, decltype(::CloseWidget), ::CloseWidget>>
{
public:
// Give the storage type a simpler name.
typedef wil::details::unique_storage<
wil::details::resource_policy<HWIDGET, decltype(::CloseWidget), ::CloseWidget>> storage_t;
// forward all base class constructors
template<typename... args_t>
explicit widget_t(args_t&& ...args) noexcept : storage_t(wistd::forward<args_t>(args)...) {}
// Here is where we can inject additional methods.
void wiggle() const noexcept
{
WiggleWidget(storage_t::get());
}
}
using unique_widget = unique_any_t<widget_t>;You can now invoke the wiggle method directly on a unique_widget:
unique_widget widget{ CreateWidget() };
widget.wiggle();Use this pattern sparingly. It works best for types (such as kernel events) where clients are not really interested in the handle itself, but rather on the operations availble to the handle.
The wil::unique_any_t template class is a smart pointer class. It
manages the lifetime of another object (the owned object). If the
unique_any_t is not managing any object, it is said to be empty.
A unique_any_t is the size of a pointer_storage, which is typically
a pointer.
The unique_any_t type is patterned after the C++ unique_ptr type. It
is movable but not copyable.
template <typename storage_t>
class unique_any_t : public storage_t;Template parameters
-
storage_t
A type that ultimately derives fromunique_storage. In most cases, this is a specialization ofunique_storageitself. (See Advanced use of unique storage for an example of using some other type.)
Member types
-
policy
Theresource_policyof theunique_storage.
-
pointer_storage
Thepointer_storagetype of the policy.
-
pointer
Thepointertype of the policy.
Constructors
-
unique_any_t(args...)
Constructor parameters are forwarded to thestorage_t. In the common case where thestorage_tis aunique_storage, it takes ownership of the passed-in pointer.
-
unique_any_t()
Creates an emptyunique_any_t.
-
unique_any_t(nullptr)
Creates an emptyunique_any_t. (Thepolicy::pointer_invalidmust bewistd::nullptr_t.)
Operators
-
operator=(unique_any_t&& other) noexcept
Closes the object currently being managed and takes ownership of the object being managed byother.
-
operator=(nullptr) noexcept
Closes the object currently being managed and leaves theunique_any_tempty. Allowed only if the underlying type is a pointer. (Thepolicy::pointer_invalidmust bewistd::nullptr_t.)
-
explicit operator bool() const noexcept
Returnstrueif an object is being managed, or orfalseif theunique_any_tis empty.
-
pointer_storage* operator&() noexcept
Closes the object that is currently being managed and returns a pointer to the internal pointer storage. (The pointer access policy must be all.) To obtain a pointer to the internal pointer storage without closing the current object, use theaddressofmethod.
-
==,!=,<,<=,>,>=comparison operators
These perform comparison on the underlyingpointer. If thepolicy::pointer_invalidiswistd::nullptr_t, then equality and inequality comparisons withnullptrare also supported.
Methods
-
pointer get() const
Returns a pointer to the object being managed, or a policy-defined invalid value (usually a null pointer) if theunique_any_tis empty. (The pointer access policy must be all or noaddress.)
-
void reset(pointer_storage ptr)(inherited)
Closes the object currently being managed and takes ownership of the new pointer.
-
void reset()(inherited)
Closes the object currently being managed and leaves theunique_any_tempty.
-
void reset(nullptr)(inherited)
Closes the object currently being managed and leaves theunique_any_tempty. Allowed only if the underlying type is a pointer. (Thepolicy::pointer_invalidmust bewistd::nullptr_t.)
-
pointer_storage release()(inherited)
Makes theunique_any_tempty and returns the object that was previously being managed. It is the caller's responsibility to close the returned object. (The pointer access policy must be all or noaddress.)
-
pointer_storage* put()
Closes the object that is currently being managed and returns a pointer to the internal pointer storage. (The pointer access policy must be all.) To obtain a pointer to the internal pointer storage without closing the current object, use theaddressofmethod.
-
pointer_storage* addressof()(inherited)
Returns a pointer to the internal pointer storage. (The pointer access policy must be all.)
-
swap(unique_any_t& other) noexcept
Exchanges the owned objects. Also available as a free functionswap(left, right)for ADL purposes.
The unique_any alias makes it more convenient to create new unique_*
types.
template <typename pointer,
typename close_fn_t,
close_fn_t close_fn,
typename pointer_access = wil::details::pointer_access_all,
typename pointer_storage = pointer,
pointer invalid = pointer(),
typename pointer_invalid = wistd::nullptr_t>
using unique_any = unique_any_t<details::unique_storage<details::resource_policy<
pointer, close_fn_t, close_fn, pointer_access, pointer_storage, invalid, pointer_invalid>>>;The template parameters are the same as those for resource_policy.