Question

How do you use std.typecons.RefCounted!(T) to make a reference-counted object in D?

I've tried to figure out what std.array.Array does internally by looking at the source, but while I can read the source, I just can't figure what a "payload" is or how it all works when there's things like bitwise struct copying involved, as well as why some things are duplicated in the internal and external structure.

Could anyone provide an example or a link on how to use it to, say, wrap a simple Win32 HANDLE?

Thanks!

Was it helpful?

Solution

Disclaimer: I haven't tested my claims, just read the documentation.

Payload is referring to what is being stored. In your case the payload is the Win32 HANDLE. Since HANDLE is just an integer you wouldn't want to do:

auto refHandle = RefCounted!HANDLE(WhatGetsMeAHandle());

Because a Windows function will need to be called when the handle goes out of scope.

In std.containers.Array what you saw was a struct called Payload, which had a field called _payload. The structure is going to be the storage of the data, accessed through _payload. This provides a level of indirection to be utilized later.

You will notice that RefCounted is actually used on the Array structure. This means the destructor for that struct will only be called when the reference count is 0. So the ~this() inside of Payload is where you would want to clean up the your HANDLE.

What is happening: since struct is a value type, every time the structure goes out of scope the destructor is called, there isn't one for Array, but Payload is wrapped in a RefCounted, the destructor for RefCounted!Payload is also called. And only when the reference count reaches zero is the destructor for Payload itself called.

Now, RefCounted itself has reference semantics, this means that having an Array a, you can then assign to auto b = a; and everything will be copied over, but RefCounted has a postblits defined meaning the data will not be copied, but the reference count will be incremented.

I will now try and provide you with a wrapper outline for what you want. It will probably help you visualize the information above, but it may not be entirely correct. Let me know if something needs fixing.

struct MyWinWrapper {
    struct Payload {
        HANDLE _payload;
        this(HANDLE h) { _payload = h; }
        ~this() { freeHandleHere(_payload); }

        // Should never perform these operations
        this(this) { assert(false); }
        void opAssign(MyWinWrapper.Payload rhs) { assert(false); }
    }

    private alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data;
    private Data _data;

    this(HANDLE h) { _data = Data(h); }
}

Since there is no default constructor for a struct you will probably want to provide a free function that returns this structure.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top