Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
87 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Reference Counting
 Smart Pointers
 Reference counting
 and STL

 Conclusion

 Get the Source
 Printable version

 


Smart Pointers

What is a pointer? A definition may be a variable which holds the address of some memory location. A more interesting way to define anything in programming is by its attributes and actions. A pointer has the attribute of holding an address, and has several actions: (assumes: int* p)

Action Example
Dereferencing int b=*p;
Member access p->something
NULL check if (p) ....

A smart pointer is a type that provides all of the above requirements, and perhaps does something extra which is useful. In this case, a smart pointer will make sure to call the addRef() subRef() for us, freeing us from worrying.

When should the reference counting be changed for an object? When ever someone acquires a pointer to the object, the counter should be incremented. When ever someone lets go of a pointer to the object, the counter should be decremented. The last one to let go of the pointer should also delete the object.

Using C++ features, here is a template class for such a smart pointer. It assumes the template parameter provides the reference counting operations.

template<class T> class RefCntPointer { public: /** Construct from normal pointer, default to NULL */ RefCntPointer(T* ptr=0) : m_ptr(ptr) { addRef(); } /** Construct from another smart pointer. Copy Constructor */ RefCntPointer(const RefCntPointer& p) : m_ptr(p.m_ptr) { addRef(); } /** Destructor. */ ~RefCntPointer() { subRef(); }

The constructors store the pointers and call addRef() to increment the counter, due to this new pointer. The destructor cleans up the counter. This is obviously not enough, since the smart pointer can be changed by assignment

/** Assignment operator. */ RefCntPointer& operator= (const RefCntPointer& p) { // Use the other operator (code reuse) return *this = p.m_ptr; } /** Assignment operator. */ RefCntPointer& operator= (T* ptr) { if (m_ptr != ptr) { subRef(); m_ptr=ptr; addRef(); } return *this; }

Note that the operator first decrements the counter for the old pointer, and then assigns the new pointer and increments its counter.

Now several operators to provide the pointer actions, and some useful conversions:

/** Dereferencing operator. Provided to behave like the normal pointer. */ T& operator * () const { return *m_ptr; } /** Member access operator. Provided to behave like the normal pointer. */ T* operator -> () const { return m_ptr; } /** Conversion operators */ operator T* () const { return m_ptr; } operator const T* () const { return m_ptr; } /** boolean test for NULL */ operator bool () const { return m_ptr!=0; } /** Address of pointer. May cause memory leaks if pointer is modified. */ T** operator & () { return &m_ptr; }

I recommend removing the last operator, to avoid problems. Use it only if absolutely necessary.

Here is the implementation of the private part of the class, which modifies the counter:

private: void addRef() { // Only change if non-null if (m_ptr) m_ptr->addRef(); } void subRef() { // Only change if non-null if (m_ptr) { // Subtract and test if this was the last pointer. if (m_ptr->subRef()) { delete m_ptr; m_ptr=0; } } } T* m_ptr; };

Usage

Using these pointers means simply to replace the declaration of the pointer:

MyObject* p;    -->    RefCntPointer<MyObject> p;

All the rest of the code can remain the same, as this type provides the same semantics as a regular pointer.




Next : Reference Counting and STL