PStack  2.0
Stack trace printer for MSVC and GCC binaries
psystem::unique_handle< T, D, kInvalidHandle > Class Template Reference

Uniquely manage a single "handle". More...

#include <unique_handle.hpp>

Inheritance diagram for psystem::unique_handle< T, D, kInvalidHandle >:
Collaboration diagram for psystem::unique_handle< T, D, kInvalidHandle >:

Type Declarations

using base = unique_handle_impl< T, D, kInvalidHandle >
 A convenient name for the base-class type.
 
using safe_address_container = psystem::internal::managed_handle_proxy< handle_type, unique_handle< handle_type, deleter_type, kInvalidHandle > >
 A safe container for altering the handle by the address-of operator.
 
using deleter_type = D
 The data-type of the clean-up facility.
 
using handle_type = T
 The data-type of the handle being managed.
 

Construction / Destruction

 unique_handle (handle_type hndl=kInvalidHandle) noexcept
 Construct an instance to manage a handle. More...
 
template<typename D2 >
 unique_handle (handle_type hndl, D2 &&deleter) noexcept
 Construct an instance to manage a handle with a custom "deleter.". More...
 
 unique_handle (unique_handle &&other) noexcept
 Transfer ownership of a handle from another unique_handle. More...
 
 ~unique_handle () noexcept
 Destroy this container, freeing the handle managed within. More...
 

Operator Overloads

unique_handleoperator= (unique_handle &&o) noexcept
 Transfer ownership of a handle into this instance. More...
 
safe_address_container operator& () noexcept
 Allow safe alteration of the handle by routines that return data by C-style output parameters. More...
 

Public Interface

deleter_typeget_deleter () noexcept
 Access the deleter instance within this class. More...
 
deleter_type const & get_deleter () const noexcept
 Access the const deleter instance within this class. More...
 
void reset (handle_type hndl=kInvalidHandle) noexcept
 Assign a new handle to be managed by this instance. More...
 
void swap (unique_handle &o) noexcept
 Swap ownership of two unique_handle instances. More...
 

Member Data

deleter_type m_deleter
 The instance that will be used to clean up the handle's resources.
 

Additional Inherited Members

- Public Types inherited from psystem::unique_handle_impl< T, D, kInvalidHandle >
using deleter_type = D
 The data-type of the clean-up facility.
 
using handle_type = T
 The data-type of the handle being managed.
 
- Public Member Functions inherited from psystem::unique_handle_impl< T, D, kInvalidHandle >
 unique_handle_impl (unique_handle_impl const &)=delete
 Disable copying because it will likely be deleted twice.
 
unique_handle_imploperator= (unique_handle_impl &)=delete
 Disable copy-assignment to prevent double-frees.
 
handle_type get () const noexcept
 Access the handle contained in this object. More...
 
handle_type release () noexcept
 Release the handle from being managed by this class. More...
 
 operator bool () const noexcept
 Determines the validity of this instance. More...
 
- Static Public Member Functions inherited from psystem::stack_allocated
static void operator delete (void *)=delete
 Individual object deletion.
 
static void operator delete[] (void *)=delete
 Array of type object deletion.
 
static void * operator new (size_t)=delete
 Individual object allocation.
 
static void * operator new[] (size_t)=delete
 Array of type allocation.
 

Detailed Description

template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
class psystem::unique_handle< T, D, kInvalidHandle >

Uniquely manage a single "handle".

A handle in this context is any opaque item of data that is used (non-opaquely) by an API. Typically handles are received from some API invocation, and will need to be "closed" by a separate API to free any resources associated with that handle.

When we say that the handle is "uniquely" managed by this instance, we simply mean that no other references to that handle exist (or if they exist, they are guaranteed not to outlive this container), and that it is this container's sole responsibility to free all resources for that handle when the container's lifetime ends.

While it is possible to use std::unique_ptr with handles, it becomes somewhat ugly (the handle type must be void*, the handle must use nullptr as its "invalid value (Windows' INVALID_HANDLE_VALUE actually maps to 0xFFFFFFFF), and so on). Frankly, it's more fun to see what we can do by creating our own implementation, so here we are.

Note
Part of this API exists within unique_handle_impl, but Doxygen isn't supplying this connection when explicit subgroupings are used. See this class template for basic accessors to the handle.
By taking the default parameters for this class template, the deleter parameter is assumed to be immutable, and the interface strips the ability to specify a deleter during construction or "reset." This assumption allows us to optimize the class such that its memory footprint is exactly the same as the handle it contains. In other words, using a unique_handle instance in this way is no more costly than using the handle directly, except that it provides a lot more functionality and exception safety. To visit the documentation for the optimized interface, see psystem::unique_handle<T,default_close_handle<T>,kInvalidHandle>.
Warning
This interface mimics std::unique_ptr, but it is not identical. Be aware of interface and behavioral differences by carefully reading documentation for individual methods.
Template Parameters
TThe type of the handle that is managed by this class.
DThe type of the "deleter" that must clean up the resources consumed by the handle that is managed by this class. The clean-up routine must match the function signature, "void(handle_type)", and it must not throw.
kInvalidHandleFor a handle to be used by this class, it must have the concept of an "invalid" handle value. This concept is analogous to nullptr for pointer types. The value passed to this template paraameter represents the invalid value marker for the handle type managed by this class.
Author
Matt Bisson
Date
5 August, 2014
Since
PSystem 2.0
Version
PSystem 2.0

Constructor & Destructor Documentation

template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
psystem::unique_handle< T, D, kInvalidHandle >::unique_handle ( handle_type  hndl = kInvalidHandle)
inlineexplicitnoexcept

Construct an instance to manage a handle.

Construction always succeeds, as exceptions are not allowed. If no parameter is specified, this constructs an instance that does not (initially) own an handle.

Warning
deleter_type must be default-constructable, and its constructor must not throw.
Parameters
[in]hndlThe handle (or invalid handle value) that this instance will manage.
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
template<typename D2 >
psystem::unique_handle< T, D, kInvalidHandle >::unique_handle ( handle_type  hndl,
D2 &&  deleter 
)
inlinenoexcept

Construct an instance to manage a handle with a custom "deleter.".

Construction always succeeds, as exceptions are not allowed.

Warning
deleter_type must be copy-constructable or move-constructable, depending on how this constructor is invoked (see deleter parameter documentation), and that constructor may not throw.
Parameters
[in]hndlThe handle (or invalid handle value) that this instance will manage.
[in]deleterThe instance of an object used to clean up the handle that it managed by this instance. This is a "universal reference" (as Scott Meyers termed it), which means:
  • If deleter is passed by value, this parameter is a const&, and will be copied into this instance.
  • If deleter is passed by r-value, this parameter is an r-value reference, and will be moved into this instance.
  • If deleter is passed by reference, this parameter is that same reference type, and will be copied into this instance.
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
psystem::unique_handle< T, D, kInvalidHandle >::unique_handle ( unique_handle< T, D, kInvalidHandle > &&  other)
inlinenoexcept

Transfer ownership of a handle from another unique_handle.

Warning
This differs from the std::unique_ptr in that it does not allow the transfer of related handle types. Often, handles are convertable types (void* to void* or long to long) that are merely obscured via a typedef. Transferring ownership of different handle types would also require changing the type of the deleter_type and the value of invalid_handle_value.
deleter_type must be move-constructable, and it must not throw.
Parameters
[in,out]otherThe unique_handle from which we're moving data.
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
psystem::unique_handle< T, D, kInvalidHandle >::~unique_handle ( )
inlinenoexcept

Destroy this container, freeing the handle managed within.

If the handle is invalid_handle_value, this method does not call the deleter. The deleter contained within this instance will also be destroyed.

Warning
Neither the deleter, nor the deleter_type::operator() may throw.

Member Function Documentation

template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
deleter_type& psystem::unique_handle< T, D, kInvalidHandle >::get_deleter ( )
inlinenoexcept

Access the deleter instance within this class.

Returns
The object that will be used to delete the handle managed in this class. This reference is valid for the lifetime of the unique_handle instance.
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
deleter_type const& psystem::unique_handle< T, D, kInvalidHandle >::get_deleter ( ) const
inlinenoexcept

Access the const deleter instance within this class.

Returns
The object that will be used to delete the handle managed in this class. This reference is valid for the lifetime of the unique_handle instance. The data within the returned instance may change as a side-effect of operator=() or reset().
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
safe_address_container psystem::unique_handle< T, D, kInvalidHandle >::operator& ( )
inlinenoexcept

Allow safe alteration of the handle by routines that return data by C-style output parameters.

Returns
A temporary object designed to track any changes to the handle when accessed by address. If the handle changes while the "safe" container tracks it, the prior handle will be released safely.
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
unique_handle& psystem::unique_handle< T, D, kInvalidHandle >::operator= ( unique_handle< T, D, kInvalidHandle > &&  o)
inlinenoexcept

Transfer ownership of a handle into this instance.

Warning
This differs from the std::unique_ptr in that it does not allow the transfer of related handle types. Often, handles are convertable types (void* to void* or long to long) that are merely obscured via a typedef. Transferring ownership of different handle types would also require changing the type of the deleter_type and the value of invalid_handle_value.
Parameters
[in,out]oThe unique_handle from which we're moving data.
Returns
A reference to this, after the assignment.
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
void psystem::unique_handle< T, D, kInvalidHandle >::reset ( handle_type  hndl = kInvalidHandle)
inlinenoexcept

Assign a new handle to be managed by this instance.

If there was a valid handle managed previously by this unique_handle instance, its resources will be cleaned up prior to assigning the new handle. If the new handle equals (==) the old handle, this method does nothing.

If no parameters are specified, this resets the unique_handle to the "invalid" state.

Parameters
[in]hndlThe new handle to manage. It need not be "valid."
template<typename T = HANDLE, typename D = default_close_handle<T>, T kInvalidHandle = INVALID_HANDLE_VALUE>
void psystem::unique_handle< T, D, kInvalidHandle >::swap ( unique_handle< T, D, kInvalidHandle > &  o)
inlinenoexcept

Swap ownership of two unique_handle instances.

Warning
deleter_type must be move-assignable, and that assignment must not throw.
Parameters
[in,out]oThe unique_handle instance that will swap handle data and deleters with this instance.
Todo:
Better "best practices" to practice for swap?

The documentation for this class was generated from the following file: