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.
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 countyou 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).
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.
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.
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.