Monday 30 July 2007

How to pronounce Bjarne Stroustrup?

Here is an audio-link in which Bjarne himself tells how to pronounce his name.

Saturday 28 July 2007

RTTI

Run Time Type Information (RTTI) is the concept which facilitates us to identify type of a polymorphic object at run time (typeid operator) and to perform type-safe down casting. There is an article already in this blog about type-safe down-casting  - dynamic_cast.

typeid is an operator which can be used to find out the dynamic type of a polymorphic object. It can be used to identify the type of the object referenced by or pointed at run time.

When do we need to use it?

Ideally never. If we design the system properly we shouldn't be using this operator. But in certain cases where we cannot avoid, we may have to use typeid operator.

Let's look at an example.

class CShape
{
    ...
};

class CCircle : public CShape
{
    ...
};

class CRectangle : public CShape
{
    ...
};

void Draw(CShape *pShape)
{
    if(typeid(*pShape) == typeid(CCircle))
    {
        cout<<"Circle"<<endl;
    }
    else if(typeid(*pShape) == typeid(CSquare))
    {
        cout<<"Circle"<<endl;
    }
}

int main()
{
    CCircle *circle = new CCircle();
    CSquare *square = new CSquare();

    Draw(circle);
    Draw(square);
}

This prints "Circle" and "Rectangle".

In function Draw(), typeid is returning the polymorphic type of the object pointed by pShape which is unknown at compilation type.

typeid uses RTTI to find out the class type at run time.

Saturday 14 July 2007

Don't ever mix Arrays with auto_ptr !

This article is in response to one of the comments for my previous article about auto_ptr.

auto_ptr which is provided by the standard C++ library wont work with arrays. It's best to avoid using auto_ptr for arrays.

What is the problem?

To understand the problem, let's take a loot at C++'s memory management background. We all know that, any "new" statement we use for dynamically creating object should be accompanied with a call to "delete" for deleting that object.

CMyClass *p = new CMyClass; //Dynamically create an object

// some other processing
...

delete p; // delete the object  

Also, if we are allocating an array of objects using new[], that must be freed using delete[] operator, which frees up all the dynamically allocated objects.

CMyClass *p = new CMyClass[5]; //Dynamically create array of objects

// some other processing
...

delete[] p; // delete the objects  

In case of auto_ptr, the destructor will just do a delete on the embedded pointer member variable.

auto_ptr::~auto_ptr()    // Destructor  
{
    delete ptr;  // free the memory
}

There's no way for auto_ptr to intelligently do delete or delete[] based on the scalar or vector dynamic objects pointed by the member pointer.

If we do

auto_ptr<int> obj(new int[10]);

When obj goes out of scope, the destructor will be called and only delete will be done on the pointer. Which ideally had to be delete []. This causes leak and may cause undefined behavior.

Its always recommended to avoid using auto_ptr with arrays.

There are few solutions proposed for this problem by Herb Sutter here.

Sunday 8 July 2007

C++0x

The next version of C++!

Bjarne offers a sneak peek at the next version of standard C++ ("C++0x") which should be complete by 2009.

C++0x

Smart Pointers

"Smart Pointers" Why do we need it?

It behaves like a pointer but does more than that. If used properly, it can enhance the code robustness, reduce memory leak headaches. 

What more does it do?

Consider a scenario, where we  use dynamic memory allocations extensively. We need to keep track of each allocation we did, for freeing it back to the system after its usage. if we forget, sure there will be a leak.

void SomeFunction()
{
    CSomeClass *ptr = new CSomeClass();

    ...

    ptr->MemberFunction();

    ...

    return; // Usual mistake! forgot to free memory. Leak!
}

Consider another case, where we allocated memory dynamically but the statement next to that thrown an exception. It contributes for a memory leak, unless the exception is caught and the memory is freed.

void SomeFunction()
{
    CSomeClass *ptr = new CSomeClass();

    ...

    ptr->MemberFunction(); // If this function throws exception, memory pointed by ptr won't be freed unless this is caught and freed

    ...
}

One more case for analysis,

CSomeClass* ptr = new CSomeClass();
CSomeClass* otherptr = ptr;

...

ptr->SomeFunction();

...

delete ptr;
ptr = NULL;    // ptr - used and safely deleted

...

otherptr->SomeFunction();   // Dangerous! otherptr is dangling

All these can happen with developers' small negligence. Using Smart pointer can avoid such nasty situations.

How?

Let's have a look at auto_ptr.

auto_ptr is one of the smart pointer templated class in Standard C++ library. It encapsulate a pointer. To embed any primitive or user defined pointer type, it has been made a templated class.

template<class T>
    class auto_ptr
    {

public:

    auto_ptr(T *p = 0);    // Constructor
    auto_ptr(const auto_ptr<T>& Y); // Copy constructor
    ~auto_ptr()    // Destructor   
    {
        delete ptr;  // free the memory
    }

    ...

private:

    T *ptr;
    };

On executing the constructor of this, it takes the ownership of the  memory pointed by the pointer. Since the instance of the auto_ptr is crated on stack, the developer need not worry about freeing the memory.

void function()
{
    auto_ptr<CSomeClass> smartPtr(new CSomeClass());
    // Use smartPtr

    ...

    // No need to worry about freeing the memory
    // When the SmartPtr goes out of scope, will call the auto_ptr's destructor which will in turn delete the embedded ptr
}

Even if there is an exception thrown before cleaning up, stack-unwinding will initiate the auto_ptr's destructor which will in turn free the memory.

Next question is how will we be able to use the smart pointer as a pointer. I mean we should be able to do the following things normally as we were doing with mere pointers,

smartPtr->SomeFunction();
*smartPtr = 3;

auto_ptr has few more overloaded functions, which facilitates us to achieve this.

T& operator*() const
{
    return *ptr;
}

T *operator->() const
{
    return ptr;
}

These two operator overloaded functions enable us to use smartPtr as regular pointer. operator *() will help in dereferencing the pointer and operator->() will do the indirection job.

Article about auto_ptr at gotw