RCArray is unsafe

Zach the Mystic via Digitalmars-d digitalmars-d at puremagic.com
Thu Mar 5 08:11:25 PST 2015


On Wednesday, 4 March 2015 at 18:05:52 UTC, Zach the Mystic wrote:
> On Wednesday, 4 March 2015 at 17:22:15 UTC, Steven 
> Schveighoffer wrote:
>> Again, I think this is an issue with the expectation of 
>> RCArray. You cannot *save* a ref to an array element, only a 
>> ref to the array itself, because you lose control over the 
>> reference count.
>
> What you need is a special RCSlave type, which is reference 
> counted not to the type of its *own* data, but to its parent's. 
> In this case, a RCArraySlave!(T) holds data of type T, but a 
> pointer to an RCArray, which it decrements when it gets 
> destroyed. This could get expensive, with an extra pointer per 
> instance than a regular T, but it would probably be safe.

A way to do this is to have a core RCData type which has the 
count itself and the chunk of memory the count refers to in type 
ambiguous form:

struct RCData {
   int count;
   // the point is that RCData can be type ambiguous
   void[] chunk;

   this(size_t size)
   {
     chunk = new void[size];
     count = 0;
   }
   void addRef() {
     ++count;
   }
   void decRef() {
     if (count && --count == 0)
       delete chunk;
   }
}

Over top of that you create a basic element type which refcounts 
an RCData rather than itself:

struct RCType(E) {
   E element;
   RCType* data;

   this(this)
   {
     data.addRef();
   }

   ~this()
   {
     data.decRef();
   }
   [...etc...]
}

Then you have an RCArray which returns RCType elements when 
indexed rather than naked types:

struct RCArray(E) {

   E[] array;
   private RCData* data;

   RCElement!E opIndex(size_t i) return
   {
     return RCElement!E(array[start + i], data);
   }

   this(E[] a)
   {
     data = new RCData(a * sizeof(a));
     array = cast(E[]) data.chunk;

   }

   this(this)
   {
     data.addRef();
   }

   ~this()
   {
     data.decRef();
   }

   //...
}

This might work. The idea is to only leak references to types 
which also have pointers to the original data.


More information about the Digitalmars-d mailing list