Borland Online And The Cobb Group Present:


February, 1995 - Vol. 2 No. 2

Other ways to perform reference counting

In the accompanying article, C++ Programming Basics - Implementing reference counting with smart pointers we show how you can declare a smart pointer class that maintains reference counts itself. However, there are three other common approaches to maintaining reference counts. Each of these methods stores the reference count with the heap object.

A template wrapper class

One obvious way to attach a reference count to a heap object is to create a template class similar to the following:

template <class T> RefCount
{ int referenceCount;
  T   heapObject;
  friend class smartPtr<T>;} 

You can create a smart pointer to one of these objects by writing

smartPtr<TWindow> wp = new RefCount<TWindow>;

Then, in the smart pointer class you replace the T* member (a pointer to the heap object) with a RefCount<T>* member.

Inside the member functions of the class, you then need to access the heap object indirectly through the RefCount<> class's heapObject data member. (This applies to the operator T*( ) and operator->( ) member functions.)

There is one significant drawback to using a template class to hold the reference count­­you can't pass constructor arguments to the enclosed object. In addition, to create a heap object in this type of template class object, the heap object's class will have to define a default constructor (a constructor with no parameters or only default parameters).

Hide the count with operator new( )

A sneaky way to maintain a reference count with a heap object is to hide the count in a special place on the heap, near the object itself (usually just below the heap object). To do this, you'll define a custom operator new( ) function that allocates enough room for the heap object and the reference-count data and then returns a pointer to the heap object.

Then, as the smart pointer class needs to increment or decrement the reference count, you can modify the value in the special location. For example, if you store the reference count as an int object that appears below the heap object, you would find the address of the reference count by subtracting the size of an int object from the heap object's address.

This technique is very powerful, but it suffers from three drawbacks. First, writing a custom operator new( ) function can be confusing for the beginner. It's not particularly difficult, but the syntax is not intuitive.

Second, you can't initialize the corresponding smart pointer objects with the return value from the standard operator new( ) function or with the address-of operator (&). If you initialize a smart pointer this way, the smart pointer will attempt to modify a hidden reference count that's not really there!

Finally, you can't call the delete( ) function for pointers that return from the custom operator new( ) function. If you try this (instead of initializing a smart pointer with this value and letting it free the memory), you're almost guaranteed to crash your program.

Deriving from a base class

If you declare a base class that will hold the reference count, you can then derive classes for reference-counted heap objects from that class. For example, if you declare the following class:

template <class T> class RefCount
{ protected:
   int referenceCount;
  friend class smartPtr<T>;}

you can derive a new class

class RefCountedHeapObject :
  public RefCount<RefCountedHeapObject>
{ // class details here };

Then you'll change your smart pointer to deal with RefCountedHeapObject pointers instead of heap pointers.

Inside the constructor and destructor for the class RefCountedHeapObject, you'll be able to directly increment and decrement the RefCount template class's referenceCount member. Then, in the destructor, you can test for the reference count reaching zero and delete the RefCountedHeapObject object if necessary.

The only significant drawback to this approach is that you'll need to derive a new ancestor of the RefCount class for any class for which you want to keep reference counts. If you create these classes yourself, you'll probably be able to derive these classes directly from the RefCount class.

However, if you want to use reference-counted smart pointers for library classes (such as TWindow from the ObjectWindows Library), you'll need to use multiple inheritance to derive from the library class and the RefCount class. While you may be hesitant to use multiple inheritance (you might be worried about member-name clashes, for example), it's fairly easy to use and implement in this situation.

This is true because most library classes on which you'll want to count the references won't have a referenceCount data member. If they do, you can simply use the scope resolution syntax

RefCount<T>::referenceCount

whenever you need to refer to the RefCount class's reference count.

Return to the Borland C++ Developer's Journal index

Subscribe to the Borland C++ Developer's Journal


Copyright (c) 1996 The Cobb Group, a division of Ziff-Davis Publishing Company. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis Publishing Company is prohibited. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Publishing Company.