Disadvantages of ARC
Adam D. Ruppe
destructionator at gmail.com
Thu Feb 6 12:23:48 PST 2014
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.
More information about the Digitalmars-d
mailing list