On Thursday, 6 February 2014 at 19:33:39 UTC, Andrei Alexandrescu wrote:
So if T is int[] and you have taken a slice into it...?

If you escape it, congratulations, you have a memory safety bug. Have fun tracking it down.

You could also offer refcounted slicing, of course (wrapping the Unique thing in a refcounter would work), or you could be converted to the church of scope where the compiler will help you catch these bugs without run time cost.

I'm not sure I understand what you are talking about.

When the reference count reaches zero, what happens? This changes based on the allocation method: you might call GC.free, you might call free(), you might do nothing, The destructor needs to know, otherwise the refcounting achieves exactly nothing! We can encode this in the type or use a function pointer for it.

struct RefCounted(T) {
    private struct Impl {
        // potential double indirection lol
        private T payload;
        private size_t count;
        private void function(T) free;
        T getPayload() { return payload; } // so it is an lvalue
        alias getPayload this;
    }
    Impl* impl;
    alias impl this;
    this(T t, void function(T) free) {
       impl = new Impl; // some kind allocation at startup lol
                        // naturally, this could also be malloc
// or take a generic allocator form the user // but refcounted definitely needs some pointer love
       impl.payload = t;
       impl.count = 1;
       impl.free = free; // gotta store this so we can free later
    }
    this(this) {
       impl.count++;
    }
    ~this() {
       impl.count--;
       if(impl.count == 0) {
           // how do we know how to free it?
           impl.free(impl.payload);

// delete impl; GC.free(impl) core.stdc.stdlib.free(impl);
           // whatever
           impl = null;
       }
    }
}


In this example, we take the reference we're counting in the constructor... which means it is already allocated. So logically, the user code should tell it how to deallocate it too. We can't just call a global free, we take a pointer instead.


So this would work kinda like this:

import core.stdc.stdlib;
int[] stuff = malloc(int.sizeof * 5)[0 .. 5];
auto counted = RefCounted!(int[])(stuff, (int[] stuff) { free(stuff.ptr); });



The allocator is not encoded in the type, but ref counted does need to know what happens when the final reference is gone. It takes a function pointer from the user for that.


This is a generically refcounting type. It isn't maximally efficient but it also works with arbitrary inputs allocated by any means.

Unique!T could do something similar, but unique would disable its postblit instead of incrementing a refcount.

Reply via email to