Thomas Sampson

“Smart Pointers”

Leave a comment

Smart pointers are objects used to manage resources which were created on the heap, and allow such resources to be deleted automatically whenever their parent smart pointer would normally go out of scope. This avoids the common problem of calling new to allocate some space on the stack for an object (returning a pointer to the object), using that pointer, and then never calling delete (causing a memory leak to occur).

Another benefit of using smart pointers is the ability to have references to heap resources counted (using reference counting). This is useful when you have a particular resource on the heap, let’s call this object x. There are n number of objects around your program which all carry a pointer to object x to use its data and functions. In this case when should object x be destroyed and the memory freed? The answer to this is typically “When n =0”. So, when the last object containing a reference to object x is removed, the reference count of object x reaches 0 and the smart pointer can then de-allocate any memory consumed by object x on the heap.

Implementation
Smart pointers have two key components. Firstly they have a pointer onto the resource being managed (in the example below this is m_data). Secondly they have a pointer to a reference counting object which allows them to keep a track of how many references there are to the managed resource, in this case rc). The reason a pointer to the reference counter is used rather than a pure data member, is that all references to the managed resource (that is, all copies of an instance of a smart pointer) need to share the same reference count as there can only be one reference count per managed object.

The example below shows a quick smart pointer implementation I wrote. There are much better tested implementations found in the stl and boost libraries but my example below just demonstrates simply what is going off.

The smart pointer object is a template class, allowing it to manage a pointer to any type of resource (but not arrays!). When the smart pointer is constructed it is given a pointer to the heap allocated object and it also creates a unique reference count for this object (From this point on, all copies of the smart pointer for the managed object share a pointer to the reference count so they can all communicate). After the first initialisation, whenever a “copy” of the resource is needed by other methods or objects (I say copy because it is only a copy of the reference they require, not a physical copy of the object) the copy constructor of the smart pointer object is called, incrementing the reference count. Whenever the smart pointer object gets destructed, the reference count for the underlying object is decremented. This way the destructor of the smart pointer can always check to see if no more references remain, and free the resources.


#include <iostream>
#include <vector>

class ref_count
{
    public:
        unsigned int count;
        ref_count() : count( 1) {}
};

template<class T>
class smart_ptr
{
    public:
        T* m_data;
        ref_count* rc;

        smart_ptr(T* data) : m_data( data), rc( new ref_count())
        {
            std::cout << "Smart pointer constructed for object "<<m_data<< "\n";
        }
        smart_ptr(const smart_ptr& source)
        {
            m_data=source.m_data;
            rc=source.rc;
            ++rc->count;
            std::cout << "Reference added for object " << m_data << "\n Ref Count = "<<rc->count<<"\n";
        }
        ~smart_ptr()
        {
            if( rc->count==1) //if last one
            {
                std::cout << "Smart pointer destructed for object "<<m_data<< "\n OBJECT RELEASED AT "<<m_data<<"\n";
                delete m_data;
            }
            else
            {
                --rc->count;
                std::cout << "Reference removed for object " << m_data << "\n Ref Count = "<<rc->count<<"\n";
            }
        }
};

class Car
{
    public:
        Car() { std::cout << "car constructed at " << this << "\n"; }
        ~Car() { std::cout << "car destructed at " << this << "\n"; }
};

void foo()
{
    std::vector<smart_ptr<Car>> garage1, garage2;
    smart_ptr<Car> car_ptr( new Car());
    garage1.push_back(car_ptr);
    garage2.push_back(car_ptr);
}

int main(int argc, char* argv[])
{
    foo();
    std::cin.get();
    return 0;
}

Advertisements

Author: tomtech999

I have recently graduated with a 1st class degree in MComp Games Software Development at Sheffield Hallam University, focusing primarily on application development in C++, with experience in graphics programming, scripting languages, DVCS/VCS and web technology. In my spare time I enjoy Drumming, Reading and Snowboarding!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s