Wednesday, November 9, 2011

How smart are the smart pointers ?

Untitled document

smart_pointer is a blessing for a carefree programmer who wants to allocate memory in heap and forget about deleting it. Sounds great. Its really tough to track a pointer and carefully release the heap memory captured.

Also it relies on the fact that its easy to clear stack than heap. So, lets see how it works.

First lets see, how can we use a smart pointer class in our program and then we will go ahead to implement it. Please follow the comments for understanding.

We take an example class

class A

{

        public:

        //This variable is meant to track the

        // number of instances of the class that are existing.

        static int count;

        //Constructor

        A()

        {

                //New instance is created so increment.

                count++;

        }

        //Copy contstructor

        A(A& obj)

        {

                //New instance is created so increment

                count ++;

        }

        //Assignment operator

        A& operator =(A& obj)

        {

                //New instance is created so increment

                count ++;

        }

        ~A()

        {

                //Instance removed, so decrement the value.

                count --;

        }

        void display()

        {

                cout << "Its me \n";

        }

};

Now we look at the main function where we will be using the smart_ptr class.

int main()

{

        //This is how we create a smart_ptr object

        // see the pointer of type A is stored inside the

        // smart_ptr object

        smart_ptr<A> ptr(new A());

        smart_ptr<A> ptr1;

        //Testing assignment operator

        ptr1 = ptr;

        //Testing self assignment

        ptr = ptr;

        // Verifying how many instances of A are there.

        cout << "A::count = " << A::count << endl;

        //Using overloaded -> operator to call

        // member functions of class A

        ptr->display();

}

Now we implement the smart_ptr class, as per the usage. So, here it is.

template <class T>

class smart_ptr

{

        private:

               // The pointer which is managed

                // by the smart_ptr class

                T* m_ptr;

                //Keeps track of the number of references

                //the allocated memmory.

int ref_count;

        public:

                smart_ptr()

                {

                        m_ptr = 0;

                        ref_count = 0;

                }

                smart_ptr(T* ptr)

                {

                        m_ptr = ptr;

                        //increment the ref count

                        //as this is the first reference

                        ref_count = 1;                

                }

                smart_ptr(smart_ptr& obj)

                {

                        cout <<  "Copy Contstructor\n";

                        ref_count++;

                }

                //Assignment  operator overload

                smart_ptr* operator =(smart_ptr& obj)

                {

                        if(&obj != this)

                        {

                                ref_count++;

                        }

                        else

                        {

                                cout << "Self assignment\n";

                        }

                }

                // Destructor

                ~smart_ptr()

                {

                        cout << "Deleteing the smart_ptr instance\n";

                        // Decrement the reference count as

                        // the instance is released

                        ref_count --;

                        if(ref_count == 0)

                        {

                                // Delete the pointer

                                // as there are no references to it.

                                delete m_ptr;

                        }

                }

                T* operator ->()

                {

                        return m_ptr;

                }

};