February 15, 2013

An examination of Smart Pointers

If you're at all familiar with C++, then you've probably had the pleasure of causing memory leaks. A memory leak is when a resource that is allocated on the heap is no longer referred to. Since you're no longer referring to it, you can't free it, and it will remain leaked until the program terminates and the Operating System comes along and cleans up the mess that you've made. Nobody wants to be known as the guy who makes messes everywhere he goes, so what's a programmer to do? Enter smart pointers. In this post we're going to examine two implementations of smart pointers, their pros and cons, and how to use them.

Here is our first smart pointer implementation.

// --------------------------------------------- SmartPointerTable.h 
#ifndef SMARTPOINTERTABLE_H
#define SMARTPOINTERTABLE_H

#include <map>
#include <iostream>

typedef std::map<void*, unsigned> rctable_t;

class SmartPointerTable
{
private:
	static bool entryExists(void* p)
	{
		rctable_t::iterator found = SmartPointerTable::s_RefCntTable.find(p);
		return found != s_RefCntTable.end();
	}

protected:
	static rctable_t s_RefCntTable;
	
	static void increment(void* p)
	{
		if(entryExists(p)) {
			s_RefCntTable[p]++;
		} else {
			s_RefCntTable[p] = 1;
		}
	}

	static void decrement(void* p)
	{
		if(entryExists(p)) {
			s_RefCntTable[p]--;
			
			if(s_RefCntTable[p] == 0)
			{
				s_RefCntTable.erase(p);
			}
		}
	}

	static unsigned getCount(void* p)
	{
		if(entryExists(p)) {
			return s_RefCntTable[p];
		} 

		return 0;
	}

	SmartPointerTable(){}
	virtual ~SmartPointerTable() = 0;
};

rctable_t SmartPointerTable::s_RefCntTable;

SmartPointerTable::~SmartPointerTable()
{
}

#endif

// --------------------------------------------- SmartPointer.h 
#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H

#include "SmartPointerTable.h"

template < typename T >
class SmartPointer : private SmartPointerTable
{
private:
	T m_Ptr;

public:
	SmartPointer(T tp)
	{
		m_Ptr = tp;
		
		if(m_Ptr != 0)
		{
			SmartPointerTable::increment(m_Ptr);
		}
	}

	~SmartPointer()
	{
		if(m_Ptr != 0)
		{
			SmartPointerTable::decrement(m_Ptr);

			if(SmartPointerTable::getCount(m_Ptr) == 0) 
			{
				delete m_Ptr;
			}
		}
	}

	T get() 
	{
		return m_Ptr;
	}
};

#endif

As you can tell, it consists of two classes. One you use (SmartPointer) and one that it uses (SmartPointerTable) to keep reference counts.

Note: Post incomplete, blog system has no drafting yet (just wrote it yesterday)