Movable resource handles
Matt Elkins via Digitalmars-d
digitalmars-d at puremagic.com
Wed Jan 27 19:55:22 PST 2016
On Thursday, 28 January 2016 at 03:38:32 UTC, Era Scarecrow wrote:
> On Thursday, 28 January 2016 at 03:02:34 UTC, Matt Elkins wrote:
>> Thanks for the response! I learned more about D just from
>> studying this example.
>
> Hmmm you might read the free online book, i'm going through it
> and finding it useful so far as a refresher.
>
> http://ddili.org/ders/d.en/index.html
Thanks. I've also got Andrei's book (The D Programming Language)
which I read before starting this.
>
>> ///// Not sure how to tag this as a code block on the forum
>
> Since the forum is text only, i like to use bbcode as [code]
> blocks (if there's a preferred method, I haven't one). So:
>
> [code]
> auto pi = 3.14159;
> [/code]
>
Cool, thanks!
>
>> /////
>> alias UR = UniqueRef!(int, theAllocator);
>> auto a = UR(41);
>> UR[] handles;
>>
>> // Both of the following lines yield:
>> // Error: ... UniqueRef is not copyable because it is
>> annotated with @disable
>> // handles ~= move(a);
>> // handles ~= a;
>> //// End code block ////
>>
>> This is essentially the same error I get on my attempts to
>> implement these semantics, as well.
>
> hmmm... You'd best be allocating the reference directly on the
> array, you should be able to add to it.
>
> [code]
> handles ~= UR(41);
> [/code]
Hm. Maybe I should show my original attempt to do this:
[code]
import std.algorithm;
struct ResourceHandle(T, DestroyPolicy, T Default = T.init)
{
// Constructors/Destructor
this(in T handle) nothrow {m_handle = handle;}
@disable this(this);
~this() {DestroyPolicy.destroy(m_handle);}
// Operators
@disable void opAssign(ref ResourceHandle lvalue);
ref ResourceHandle opAssign(ResourceHandle rvalue)
{swap(m_handle, rvalue.m_handle); return this;}
ref ResourceHandle opAssign(in T handle)
{DestroyPolicy.destroy(m_handle); m_handle = handle; return this;}
// Methods
T get() const nothrow {return m_handle;}
T release() nothrow {T result = m_handle; m_handle = Default;
return result;}
private:
T m_handle = Default;
}
unittest
{
static uint lastDestroyed;
struct Destroyer {static void destroy(uint resource)
{lastDestroyed = resource;}}
alias RH = ResourceHandle!(uint, Destroyer, 0u);
assert (lastDestroyed == 0);
{auto handle = RH(7);}
assert (lastDestroyed == 7);
{
auto handle = RH(8);
assert(handle.release() == 8);
assert(handle.get() == uint.init);
assert (lastDestroyed == 7);
}
assert (lastDestroyed == uint.init);
{
auto handle = RH(8);
assert(handle.get() == 8);
assert (lastDestroyed == uint.init);
}
assert (lastDestroyed == 8);
auto handle1 = RH(1);
auto handle2 = RH(2);
assert(handle1.get() == 1);
assert(handle2.get() == 2);
assert (lastDestroyed == 8);
handle2 = handle1.release();
assert (lastDestroyed == 2);
assert (handle2.get() == 1);
assert (handle1.get() == uint.init);
RH[] handles;
//handles ~= RH(3); // Fails because post-blit constructor is
@disabled
}
[/code]
By way of comparison, in C++ I could do something like this
(typing this directly into the post without checking it, so may
have syntax errors:
[code]
// Compare to the last two lines of the unit test
using RH = std::unique_ptr<unsigned int, Destroyer>;
std::vector<RH> handles;
handles.push_back(RH(3)); // Moves in the "3" resource
[/code]
Since D appears to lack an equivalent for C++'s move semantics, I
wonder whether this is even possible to achieve? Maybe if there
were some way to test for lvalue vs rvalue in the copy
constructor...except that D has a post-blit constructor, not a
copy constructor. I suspect I am handicapping myself by thinking
in C++ terms.
More information about the Digitalmars-d
mailing list