Templates and Smart Pointers
C++ allows you to create “smart pointer” classes that encapsulate pointers and override pointer operators to add new functionality to pointer operations. Templates allow you to create generic wrappers to encapsulate pointers of almost any type.
The following code outlines a simple reference count garbage collector. The template class Ptr<T> implements a garbage collecting pointer to any class derived from RefCount.
#include <stdio.h>
#define TRACE printf
class RefCount {
int crefs;
public:
RefCount(void) { crefs = 0; }
~RefCount() { TRACE("goodbye(%d)\n", crefs); }
void upcount(void) { ++crefs; TRACE("up to %d\n", crefs);}
void downcount(void)
{
if (--crefs == 0)
{
delete this;
}
else
TRACE("downto %d\n", crefs);
}
};
class Sample : public RefCount {
public:
void doSomething(void) { TRACE("Did something\n");}
};
template <class T> class Ptr {
T* p;
public:
Ptr(T* p_) : p(p_) { p->upcount(); }
~Ptr(void) { p->downcount(); }
operator T*(void) { return p; }
T& operator*(void) { return *p; }
T* operator->(void) { return p; }
Ptr& operator=(Ptr<T> &p_)
{return operator=((T *) p_);}
Ptr& operator=(T* p_) {
p->downcount(); p = p_; p->upcount(); return *this;
}
};
int main() {
Ptr<Sample> p = new Sample; // sample #1
Ptr<Sample> p2 = new Sample; // sample #2
p = p2; // #1 will have 0 crefs, so it is destroyed;
// #2 will have 2 crefs.
p->doSomething();
return 0;
// As p2 and p go out of scope, their destructors call
// downcount. The cref variable of #2 goes to 0, so #2 is
// destroyed
}
Classes RefCount
and Ptr<T>
together provide a simple garbage collection solution for any class that can afford the int
per instance overhead to inherit from RefCount
. Note that the primary benefit of using a parametric class like Ptr<T>
instead of a more generic class like Ptr
is that the former is completely type-safe. The preceding code ensures that a Ptr<T>
can be used almost anywhere a T*
is used; in contrast, a generic Ptr
would only provide implicit conversions to void*
.
For example, consider a class used to create and manipulate garbage collected files, symbols, strings, and so forth. From the class template Ptr<T>
, the compiler will create template classes Ptr<File>
, Ptr<Symbol>
, Ptr<String>
, and so on, and their member functions: Ptr<File>::~Ptr()
, Ptr<File>::operator File*()
, Ptr<String>::~Ptr()
, Ptr<String>::operator String*()
, and so on.