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:
You can create a smart pointer to one of these objects by writing
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:
you can derive a new class
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
whenever you need to refer to the RefCount class's
reference count.
A template wrapper class
template <class T> RefCount
{ int referenceCount;
T heapObject;
friend class smartPtr<T>;}
smartPtr<TWindow> wp = new RefCount<TWindow>;
Hide the count with operator new( )
Deriving from a base class
template <class T> class RefCount
{ protected:
int referenceCount;
friend class smartPtr<T>;}
class RefCountedHeapObject :
public RefCount<RefCountedHeapObject>
{ // class details here };
RefCount<T>::referenceCount
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.