Boost logo

Boost :

Subject: Re: [boost] [RFC] unique_val (handles, IDs, descriptors...)
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2018-02-15 07:10:06


The idea is correct, but the implementation is a little naiive IMHO.

I recently wrote a very similar thing for abstracting OpenGL object handles
and file handles. Brook's comment is correct. You'll need some kind of
policy class to handle:

1. creation
2. destruction
3. testing for an invalid handle (not always zero)
4. move/move-construct
5. (possibly) handle duplication upon copy (some handles, e.g. FDs allow
this)
6. preventing the moving of one kind of handle into another (e.g. an OpenGL
VertexArray is a GLuint and so is a ShaderProgram, but they are not
conceptually compatible)

Also, some resources can be created in groups (see glGenVertexArrays). This
argues for the idea of an array/vector version, or at least a method on the
policy class for vector-like construction.

To me, a more expressive name might be:

template<class HandleService>
struct unique_handle;

Where HandleService defines the service/policy class with services such as:

using native_handle_type = <e.g. GLuint>;

auto construct(...args) -> native_handle_type;
void destroy(native_handle_type&) noexcept;
bool empty(native_handle_type const&) noexcept;
auto move_construct(native_handle_type&& from) noexcept ->
native_handle_type;
auto move_assign(native_handle_type&& from, native_handle_type& to)
noexcept -> void;

// with option dup/copy methods if the underlying handle supports them
auto copy_or_duplicate(native_handle const&) -> native_handle;

Further:
It is possible that handles exist within an outer context, such as a
resource cache with automatic lifetime management. In this case the
HandleService would need to be a value carried in the unique_handle, so it
can track the state of the outer container.

Therefore the HandleService class in most cases will be an empty functor,
but could also hold a reference to container state.

Further Again:

unique_handle might have a method on it called share() which returns a
shared_handle<HandleService>. Much like std::future::share.

On 14 February 2018 at 21:18, Miguel Ojeda via Boost <boost_at_[hidden]>
wrote:

> Hi all,
>
> While working on a medium-sized project, I had to wrap quite some
> handles, IDs, descriptors, etc. into RAII classes. Somehow, writing
> those and making them movable seemed more verbose than needed. I
> searched in the STL and Boost for something already implemented, but
> nothing seemed to come up. I decided to write my own prototype to see
> whether I was missing something important; but actually using it in my
> project felt quite natural and simple.
>
> At this point, I asked for a second opinion from a well-known expert
> (thanks Scott!) and he agreed that it seemed like a reasonable idea
> but, of course, he would also be surprised if others haven't come up
> with something similar. So I polished it up a bit and uploaded it to:
>
> https://github.com/ojeda/unique_val
>
> Below you have the introduction inlined [1].
>
> If you have the time, please take a look (specially to the Rationale)
> and let me know your comments. The code itself is very short and
> straightforward.
>
> If you already have this class/template in Boost somewhere that I
> missed, please let me know! Otherwise, if you think this could be
> interesting to put into Boost in some existing library (not sure
> which) or as a new tiny library, I would be glad to make the effort to
> expand it, clean it up, etc.
>
> Thank you!
> Miguel
>
> [1]
>
> """
> A single-header header-only library for representing unique values
> (handles, IDs, descriptors...) that default to a value on move for
> C++11, C++14 and C++17.
>
> It simplifies writing resource-owning classes (RAII) with move
> semantics support for resources with handles, IDs or descriptors that
> are supposed to be used as unique values, not as unique pointers. For
> instance, it can be used with non-pointer handlers (like the `int`
> file/socket descriptors in POSIX) and with opaque pointer handlers
> (like the `HWND` handles in the Win32 API).
>
> As such, it can be used as an alternative to `std::unique_ptr` with or
> without custom deleter, specially for resources that use a non-pointer
> type or resources that are not simply heap-allocated.
>
> It does not have any overhead compared to using the original type. It
> supports booleans, integers, pointers and enumerations. The default
> value can be different than the default-constructed value (i.e.
> different than 0, nullptr, etc.).
> """
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/
> mailman/listinfo.cgi/boost
>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk