Sunday, September 9, 2012

Smart Pointers in C++

Hi this is my first post in a series of posts on memory management in C++.

Why smart pointers?

Suppose we have a code like


class A {
public:
    A();
    void someMethod();
    void someOtherMehtod();

    // .....
};
void fooBar(A* a);
void foo()
{
    A* a = new A();
    a->someMethod();

    // do something with a
    fooBar(a);
    delete a;
}
This is a simple a straight forward code, we are creating an instance of "A", passing "a" as an argument to "foo" function and then deleting it. Pretty nice until now :)

But their is a potential memory leak here. In order to release memory obtained through "new" operator we must use "delete" operator, otherwise memory will leak. Suppose if we do not remember to call "delete" or suppose inside "fooBar()" implementation an exception occurs, then control will never return back and "delete a;" is never executed and we will be leaking memory :(
Same is true when you use any third party API, it can also raise an exception. Remember we are only sure about our own code, we cannot guarantee any one else code.

The simple solution is to use "auto_ptr"(a smart pointer) provided by C++ standard library.
A simple "auto_ptr" class might look like


template<typename T> class auto_ptr {
public:
    explicit auto_ptr(T* t = 0)
        : m_ptr(t)
    {
    }
    virtual ~auto_ptr()
    {
        delete m_ptr;
    }
    T& operator*()
    {
        return *m_ptr;
    }
    T* operator->()
    {
        return m_ptr;
    }
    T* get() const
    {
        return m_ptr;
    }
    // some other methods
private:
    T* m_ptr;
};


As you can see "auto_ptr" is just a wrapper around a raw pointer. It guaranties object deletion when it goes out of scope.
Now in order to use "auto_ptr", our implementation of "foo()" will look like

void foo()
{
    auto_ptr<A> a(new A());
    a->someMethod();
    // do something with a
    fooBar(a.get());
}
Or we can use auto_ptr provided by C++ standard library

void foo()
{
    std::auto_ptr<A> a(new A());
    a->someMethod();
    // do something with a
    fooBar(a.get());
}

As you can see their is no need for "delete" here, auto_ptr guarantees us it will call "delete" operator no matter what happens inside fooBar().
Another advantage is we can still use dereference operator with smart pointers just like with raw pointer. Because it has overloaded "*" and "->" operators inside "auto_ptr" class.
"auto_ptr" is the most simplest kind of smart pointers. Their are many more available, which have their own memory management policy.

Why to use smart pointers?

It makes our code less buggy.

void foo()
{
    A* a1 = new A();
    A* a2 = a1;
    a1->someMethod();
    delete a1;
    a1->someOtherMehtod(); // Ohhh a1 is dangling, and we will get a crash here
    a1 = NULL; // a1 is now no more dangling
    a2->someOtherMehtod(); // a1 is still dangling here
}
It is safe to use, it automatically initialises its instance member through default constructor.

It make our code partially garbage collected, we no more need to call delete, it does this for us :)

I will talk about more on smart pointers with introduction to some other kinds available.


No comments:

Post a Comment