Reference-counted pointers

Back to Deprecated

A reference-counted pointer is an object which tracks the number of reference-counted pointers referencing a given object, and destructs the tracked object when this number drops to zero.

Theory

C++, as defined in the 2003 standard, does not have garbage collection. This means that all dynamically allocated memory must be properly taken care of and deallocated when no longer needed. Unfortunately, when using plain pointers, it is easy to forget to deallocate memory, which leads to resources being wasted. In addition, failing to destruct some objects might end-up locking some other resources than memory, for example a file, from other processes.

The solution to this problem is called RAII, which is an abbreviation for Resource Acquisation Is Initialization. It means the following. When you acquire a resource, be it by allocating memory or by opening a file, you create an object in the stack to take care of the resource. When the object is destroyed at the end of its scope, the object automatically frees the resource in its destructor. This way the burden of freeing a resource is removed from the programmer, leading to code that is much more robust.

The RAII technique can be generalized to what are called reference-counted pointers. We shall abbreviate these simply as counted pointers. The idea is again to create an object to take care of dynamically allocated memory. However, one now allows multiple objects to take care of the same memory block. When such an object acquires a memory block, it increments a unique count that is associated with the memory block. In turn, when the object is destroyed, it decrements the count, and if it becomes zero, also frees the memory block. This way counted pointers implement a simplified garbage collection system. Strictly speaking, it is an abuse of terminology to call these objects pointers since they are not. However, the terminology is somewhat justified by noticing that these objects work in the same way as pointers do.

There is one general problem with counted pointers that you should be aware of. If inside a memory block A, you have a counted pointer that counts references to a memory block B, and inside the memory block B, you have a counted pointer that counts references to a memory block A, the memory blocks will never be deallocated automatically. This is called a cyclic reference. A cyclic reference can also form from a bigger chain of references which form a loop. This cyclic reference problem can be solved by using a so-called weak pointer in some position of the loop. This simply means that one of the directions is not counted as a reference.

Practice

Pastel provides an invasive technique for reference counting. This means that any class wishing to use CountedPtr or WeakPtr for reference counting must derive from ReferenceCounted. This also means that Pastel’s counted pointers can’t be used with native types or with objects whose class you can’t modify. If you want a non-invasive counted pointer instead, usable for native types also, see the boost::shared_ptr in the Boost library.

While the technique Pastel uses is a bit restrictive, we decided to go with it anyway. This is because the technique has some specific advantages over the non-invasive techniques. These include:

Apart from the invasiveness of the technique Pastel uses, we should also mention as disadvantages that the reference count adds one integer amount of storage requirements for a class plus the storage that is needed when the class contains virtual functions. This is a bit unideal if the object is actually allocated from the stack.

Files

A base class for CountedPtr reference counted objects

Counted pointer module

CountedPtr class

A reference counted smart-pointer

WeakPtr class

A non-counting smart-pointer to breaking cyclic references