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