Loading...
Searching...
No Matches
lomiri::util::ResourcePtr< R, D > Class Template Referencefinal

Class to guarantee deallocation of arbitrary resources. More...

`#include <lomiri/util/ResourcePtr.h>`

## Public Types

typedef R | element_type
typedef D | deleter_type

## Public Member Functions

| ResourcePtr (ResourcePtr const &)=delete
ResourcePtr & | operator= (ResourcePtr const &)=delete
| ResourcePtr (D d)
| ResourcePtr (R r, D d)
| ResourcePtr (ResourcePtr &&r)
ResourcePtr & | operator= (ResourcePtr &&r)
| ~ResourcePtr () noexcept
void | swap (ResourcePtr &other)
void | reset (R r)
R | release ()
void | dealloc ()
R | get () const
bool | has_resource () const noexcept
| operator bool () const noexcept
D & | get_deleter () noexcept
D const & | get_deleter () const noexcept
bool | operator== (ResourcePtr const &rhs) const
| Compares two instances for equality.
bool | operator!= (ResourcePtr const &rhs) const
| Compares two instances for inequality.
bool | operator< (ResourcePtr const &rhs) const
| Returns `true` if `this` is less than `rhs`.
bool | operator<= (ResourcePtr const &rhs) const
| Returns `true` if `this` is less than or equal to `rhs`.
bool | operator> (ResourcePtr const &rhs) const
| Returns `true` if `this` is greater than `rhs`.
bool | operator>= (ResourcePtr const &rhs) const
| Returns `true` if `this` is greater than or equal to `rhs`.

## Detailed Description

template<typename R, typename D>
class lomiri::util::ResourcePtr< R, D >

Class to guarantee deallocation of arbitrary resources.

ResourcePtr is a generalized resource pointer that guarantees deallocation. It is intended for arbitrary pairs of allocate/deallocate functions, such as `XCreateDisplay`/`XDestroyDisplay`.

The resource managed by this class must be default-constructible, copy-constructible, and assignable.

ResourcePtr essentially does what `std::unique_ptr` does, but it works with opaque types and resource allocation functions that do not return a pointer type, such as `open()`.

ResourcePtr is thread-safe.

Note
  Do not use reset() to set the resource to the "no resource allocated" state. Instead, call dealloc() to do this. ResourcePtr has no idea what a "not allocated" resource value looks like and therefore cannot test for it. If you use reset() to install a "no resource allocated" value for for the resource, the deleter will eventually be called with this value as its argument. Whether this is benign or not depends on the deleter. For example, `XFree()` must not be called with a `nullptr` argument.
  Do not call get() or release() if no resource is currently allocated. Doing so throws `std::logic_error`.

Here is an example that shows how to use this for a `glXCreateContext`/`GLXDestroyContext` pair. The returned `GLXContext` is a pointer to an opaque type; `std::unique_ptr` cannot be used for this, even with a custom deleter, because the signatures of the allocator and deallocator do not match `unique_ptr`'s expectations.

ResourcePtr<GLXContext, std::function<void(GLXContext)>> context =
std::bind(&glXDestroyContext, display_, std::placeholders::_1);
lomiri::util::ResourcePtr
Class to guarantee deallocation of arbitrary resources.
Definition ResourcePtr.h:121

display_ is declared as

Display* display_;

in this case.

The deleter for the resource can return any type (including int, such as returned by `XDestroyWindow()`), and it must accept a single argument of the resource type (`GLXContext` in this example).

`glXDestroyContext()` expects the display pointer as the first argument so, for this example, `std::bind` converts the binary `glXDestroyContext()` function into a unary function suitable as the deleter.

Rather than mucking around with `std::bind`, it is often easier to use a lambda. For example:

ResourcePtr<GLXContext, std::function<void(GLXContext)>> context =
[this](GLXContext c) { this->dealloc_GLXContext(c); };

This calls a member function `dealloc_GLXContext()` that, in turn calls `glXDestroyContext()` and supplies the display parameter.

Note
  Even though you can use ResourcePtr to deallocate dynamic memory, doing so is discouraged. Use `std::unique_ptr` instead, which is better suited to the task.

## Member Typedef Documentation

## deleter_type

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::deleter_type

A function object or lvalue reference to a function or function object. The ResourcePtr calls this to deallocate the resource.

## element_type

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::element_type

The type of resource managed by this ResourcePtr.

## Constructor & Destructor Documentation

## ResourcePtr() [1/4]

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::ResourcePtr | ( | ResourcePtr< R, D > const & |  | ) |

delete

Deleted

## ResourcePtr() [2/4]

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::ResourcePtr | ( | D | d | ) |

explicit

Constructs a ResourcePtr with the specified deleter. No resource is held, so a call to has_resource() after constructing a ResourcePtr this way returns `false`.

## ResourcePtr() [3/4]

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::ResourcePtr | ( | R | r,
|  | D | d
| ) |  |

Constructs a ResourcePtr with the specified resource and deleter. has_resource() returns `true` after calling this constructor.

Note
  It is legal to pass a resource that represents the "not allocated" state. For example, the following code passes the value `-1` to `close()` if the call to `open()` fails:

ResourcePtr<int, decltype(&::close)> fd(::open("/somefile", O_RDONLY), ::close);

When the ResourcePtr goes out of scope, this results in a call to `close(-1)`. In this case, the call with an invalid file descriptor is harmless (but causes noise from diagnostic tools, such as `valgrind`). However, depending on the specific deleter, passing an invalid value to the deleter may have more serious consequences.

To avoid the problem, you can delay initialization of the ResourcePtr until you know that the resource was successfully allocated, for example:

int tmp_fd = ::open(filename.c_str(), O_RDONLY);
if (tmp_fd == -1)
{
throw FileException(filename.c_str());
}
util::ResourcePtr<int, decltype(&::close)> fd(tmp_fd, ::close(fd));
lomiri::FileException
Exception to indicate file I/O errors, such as failure to open or write to a file.
Definition LomiriExceptions.h:112

Alternatively, you can use a deleter function that tests the resource value for validity and avoids calling the deleter with an invalid value:

util::ResourcePtr<int, std::function<void(int)>> fd(
::open(filename.c_str(), O_RDONLY),
[](int fd) { if (fd != -1) ::close(fd); }
);

Note that, with the second approach, a call to get() will succeed and return -1 rather than throwing an exception, so the first approach is the recommended one.

## ResourcePtr() [4/4]

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::ResourcePtr | ( | ResourcePtr< R, D > && | r | ) |

Constructs a ResourcePtr by transferring ownership from `r` to `this`.

If the resource's move or copy constructor throws, the exception is propagated to the caller. The strong exception guarantee is preserved if it is provided by the resource.

## ~ResourcePtr()

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::~ResourcePtr | ( |  | ) |

noexcept

Destroys the ResourcePtr. If a resource is held, it calls the deleter for the current resource (if any).

## Member Function Documentation

## dealloc()

template<typename R , typename D >

void lomiri::util::ResourcePtr< R, D >::dealloc | ( |  | ) |

Calls the deleter for the current resource.

If the deleter throws, the resource is considered in the "not allocated" state, that is, no attempt is made to call the deleter again for this resource.

## get()

template<typename R , typename D >

R lomiri::util::ResourcePtr< R, D >::get | ( |  | ) | const

inline

Returns the current resource. If no resource is currently held, get() throws `std::logic_error`.

Returns
  The current resource (if any).

If the resource's copy constructor throws an exception, that exception is propagated to the caller.

Exceptions

  std::logic_error | if has_resource() is false.

## get_deleter() [1/2]

template<typename R , typename D >

D const & lomiri::util::ResourcePtr< R, D >::get_deleter | ( |  | ) | const

inline noexcept

Returns
  The deleter for the resource.

## get_deleter() [2/2]

template<typename R , typename D >

D & lomiri::util::ResourcePtr< R, D >::get_deleter | ( |  | ) |

inline noexcept

Returns
  The deleter for the resource.

## has_resource()

template<typename R , typename D >

bool lomiri::util::ResourcePtr< R, D >::has_resource | ( |  | ) | const

inline noexcept

Returns
  `true` if `this` currently manages a resource; `false`, otherwise.

## operator bool()

template<typename R , typename D >

lomiri::util::ResourcePtr< R, D >::operator bool | ( |  | ) | const

inline explicit noexcept

Synonym for has_resource().

## operator!=()

template<typename R , typename D >

bool lomiri::util::ResourcePtr< R, D >::operator!= | ( | ResourcePtr< R, D > const & | rhs | ) | const

inline

Compares two instances for inequality.

If the underlying `operator==` throws an exception, that exception is propagated to the caller.

Note
  This operator is available only if the underlying resource provides `operator==`.

## operator<()

template<typename R , typename D >

bool lomiri::util::ResourcePtr< R, D >::operator< | ( | ResourcePtr< R, D > const & | rhs | ) | const

Returns `true` if `this` is less than `rhs`.

An instance that does not hold a resource is less than any instance that holds a resource.

If the underlying `operator<` throws an exception, that exception is propagated to the caller.

Note
  This operator is available only if the underlying resource provides `operator<`.

## operator<=()

template<typename R , typename D >

bool lomiri::util::ResourcePtr< R, D >::operator<= | ( | ResourcePtr< R, D > const & | rhs | ) | const

Returns `true` if `this` is less than or equal to `rhs`.

An instance that does not hold a resource is less than any instance that holds a resource. Two instances that do not hold a resource are equal.

If the underlying `operator<` or `operator==` throws an exception, that exception is propagated to the caller.

Note
  This operator is available only if the underlying resource provides `operator<` and `operator==`.

## operator=() [1/2]

template<typename R , typename D >

ResourcePtr< R, D > & lomiri::util::ResourcePtr< R, D >::operator= | ( | ResourcePtr< R, D > && | r | ) |

Assigns the resource held by `r`, transferring ownership. After the transfer, `r.has_resource()` returns `false`, and `this.has_resource()` returns the value of `r.has_resource()` prior to the assignment.

## operator=() [2/2]

template<typename R , typename D >

ResourcePtr & lomiri::util::ResourcePtr< R, D >::operator= | ( | ResourcePtr< R, D > const & |  | ) |

delete

Deleted

## operator==()

template<typename R , typename D >

bool lomiri::util::ResourcePtr< R, D >::operator== | ( | ResourcePtr< R, D > const & | rhs | ) | const

Compares two instances for equality.

Two instances that do not hold a resource are equal. An instance that does not hold a resource is not equal to any instance that holds a resource.

If the underlying `operator==` throws an exception, that exception is propagated to the caller.

Note
  This operator is available only if the underlying resource provides `operator==`.

## operator>()

template<typename R , typename D >

bool lomiri::util::ResourcePtr< R, D >::operator> | ( | ResourcePtr< R, D > const & | rhs | ) | const

inline

Returns `true` if `this` is greater than `rhs`.

An instance that holds a resource is greater than any instance that does not hold a resource.

If the underlying `operator<` or `operator==` throws an exception, that exception is propagated to the caller.

Note
  This operator is available only if the underlying resource provides `operator<` and `operator==`.

## operator>=()

template<typename R , typename D >

bool lomiri::util::ResourcePtr< R, D >::operator>= | ( | ResourcePtr< R, D > const & | rhs | ) | const

inline

Returns `true` if `this` is greater than or equal to `rhs`.

An instance that holds a resource is greater than any instance that does not hold a resource. Two instances that do not hold a resource are equal.

If the underlying `operator<` throws an exception, that exception is propagated to the caller.

Note
  This operator is available only if the underlying resource provides `operator<`.

## release()

template<typename R , typename D >

R lomiri::util::ResourcePtr< R, D >::release | ( |  | ) |

inline

Releases ownership of the current resource without calling the deleter.

Returns
  The current resource.

Exceptions

  std::logic_error | if has_resource() is false.

## reset()

template<typename R , typename D >

void lomiri::util::ResourcePtr< R, D >::reset | ( | R | r | ) |

Assigns a new resource to `this`, first deallocating the current resource (if any).

If the deleter for the current resource throws an exception, the exception is propagated to the caller. In this case, the transfer of `r` to `this` is still carried out so, after the call to reset(), `this` manages `r`, whether the deleter throws or not. (If the deleter does throw, no attempt is made to call the deleter again for the same resource.)

## swap()

template<typename R , typename D >

void lomiri::util::ResourcePtr< R, D >::swap | ( | ResourcePtr< R, D > & | other | ) |

Swaps the resource and deleter of `this` with the resource and deleter of `other` using argument dependent lookup (ADL).

If the underlying swap throws an exception, that exception is propagated to the caller, and the resource held by the ResourcePtr is unchanged.

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

- include/lomiri/util/ResourcePtr.h