Making a reference-counted object

A common technique to manage resources is reference counting. D's structs provide the necessary infrastructure to automate reference counting.

How to do it…

In order to make a reference-counted object, perform the following steps:

  1. Write a struct with its only data member being a pointer to the object. You may write a nested struct to hold the data, or it may be a pointer to a library.
  2. Add alias this to the pointer so that operations will be automatically forwarded to it.
  3. Make a constructor, if possible, or a static factory method that acquires the object and increases the reference count.
  4. Write a postblit that increases the reference count.
  5. Write a destructor that decreases the reference count and frees the object if necessary.
  6. Keep in mind that the data pointer may be null, and check for that in each function. Consider the following code:
    struct RefCountedObject {
      private struct Implementation {
        /* other contents here */
    
        int refcount;
      }
    
      Implementation* data;
    
      alias data this;
    
      static RefCountedObject create() {
        RefCountedObject o = void;
        o.data = new Implementation();
        o.data.refcount = 1;
        writeln("Created."); // so we can see it in action
        return o;
      }
    
      this(this) {
        if(data is null) return;
        data.refcount++;
        writeln("Copied.   Refcount = ", data.refcount);
      }
    
      ~this() {
        if(data is null) return;
        data.refcount--;
        writeln("Released. Refcount = ", data.refcount);
        if(data.refcount == 0)
        writeln("Destroyed.");
      }
    }

How it works…

The general idea of reference counting is to increment the count every time the reference is copied and decrement it every time a reference ceases to exist. D's structs provide two functions that can do exactly this: postblits and destructors.

When a struct object is copied, the data is first blitted (bit-block transfer; a straightforward copy of the object's memory) to the new location (a shallow copy operation). Then the postblit function, if present, is called on the recipient object. The postblit is defined with the syntax this(this) { /* code */ }.

Whenever struct provably ceases to exist—goes out of scope after being left behind by a thrown exception, being written over, or being collected by the garbage collector—its destructor is called, if present. The destructor is defined with the syntax ~this() { /* code */ }.

It is important that the reference count is stored separately from struct. If the count were a regular member variable, it would be copied along with the reference, making it useless. A static member variable would be shared across all instances of the struct, which makes it unsuitable to manage distinct objects as well. Instead, we use a pointer to the object with the reference count.

Tip

If we were using a C object with functions to add and remove references, we could hold the pointer to the C object and simply call those functions in the postblit and destructor, respectively.

Since our key member is a pointer, we need to remember that it may be null and offer a way to initialize it. Since D's structs cannot have default constructors, we instead use a factory function. The factory function acquires the function and initializes the reference count to one.

Afterward, we can use the object normally, thanks to alias this. All method calls will be forwarded to the inner object. The alias this declaration also allows implicit conversion to the inner object's type, which could break the reference counting encapsulation. This is why we made Implementation private. If it is not possible to make the inner object private, avoid this situation by either writing forwarding functions yourself (this can be automated with code generation, which we'll cover later in the book) or implement a code review policy, prohibiting the direct declaration of the inner object's type.

See also

  • http://dlang.org/phobos/std_typecons.html#RefCounted is a standard library wrapper that adds reference counting to an existing object. It will not (at the time of writing this book) work with class objects, nor will it give you the same level of control as doing it yourself.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.254.151