Wrapping a C library with its own GC + classes vs refcounted structs

aldanor via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Jan 9 16:25:22 PST 2015


Hi all,

I was wondering what's the most D-idiomatic way of dealing with a 
C library (or rather writing wrappers for a C library) that does 
its own GC via reference counting. The objects are identified and 
passed around by integer ids only; most functions like "find me 
an object foo in object bar" return an id and increase a refcount 
internally; in rare cases, a borrowed reference is returned. 
Whenever refcount drops to zero, the id becomes invalid and the 
memory (and possibly the id as well) gets eventually reused. Some 
C functions may explicitly or implicitly release IDs so there's 
also a problem of tracking whether a live D object refers to a 
live C object.

Since the main concern here is wrapping the C library, the only 
data that is stored in D objects is the object id, so the objects 
are really lightweight in that sense. However, there's a logical 
hierarchy of objects that would be logical to reflect in D types 
either via inheritance or struct aliasing.

The main question here is whether it's most appropriate in this 
situation to use D classes and cross the fingers relying on D's 
GC to trigger C's GC (i.e., ~this() to explicitly decrease 
refcount in the C library), or use refcounted structs (or 
something else?). I think I understand how RefCounted works but 
can't see how exactly it is applicable in cases like this or what 
are the consequences of using it.

My initial naive guess was to use classes in D to encapsulate 
objects (to be able to use inheritance), so the code for the base 
class looks along the lines of:

class ID {
     protected int id;
     private static shared Registry registry;

     this(int id) { // assume that refcount was already increased 
in C
         this.id = id;
         registry.store(this); // store weakref to track zombie 
objects
     }

     ~this() @nogc {
         if (c_is_valid(id) && c_refcount(id) > 0)
             c_decref(id);
         registry.remove(this);
     }
}

class ConcreteTypeA(ID) { ... }
class ConcreteTypeB(ID) { ... }

where the weak static registry is required to keep track of live 
D objects that may refer to dead C objects and has to be 
traversed once in a while.

However there's something sketchy about doing it this way since 
the lifetimes of objects are not directly controlled, plus there 
are situations where a temporary object is only required to exist 
in function's scope and is naturally expected to be released upon 
exit from the scope.

A related thread: 
http://forum.dlang.org/thread/lmneclktewajznvfdawu@forum.dlang.org


More information about the Digitalmars-d-learn mailing list