Wednesday, 15 August 2007

Zombie

This article talks about handling a failing constructor.

What does it mean when I say Failing Constructor?

Consider a situation where we have written a constructor for a class and for some reasons it fails before fully executing the constructor. Constructor wont return any value, so it wont be possible for us to tell whether the constructor is fully executed or not.

What's the state of the object in this case?

Its a zombie object, because of the reason that the construction of the object has not happened in the expected way.

What's the problem with zombie objects?

Constructor has not executed completely, it has ended unexpectedly. This means the object has not been constructed. Hence, Destructor for the same object wont be executed. We will encounter problem, If we have done any dynamic allocations or opened any resource handles in the constructor before it fails, because the memory allocated wont be freed since the code for freeing up the memory or closing the resource handles usually sits in the destructor.

Code below explains this situation,

class CTest
{
public:
    // Constructor
    CTest();

    // Destructor
    ~CTest();

private:
    // Member pointer variables
    char *m_ptr1;
    char *m_ptr2;
};

// Constructor definition
CTest::CTest()
{
    // Init member pointers
    m_ptr1 = m_ptr2 = NULL;

    m_ptr1 = new char[100]; // Assume this succeeds

    m_ptr2 = new char[100]; // Assume this fails here!

    // Other processing

    ...
}

// Destructor definition
CTest::~CTest()
{
    delete [] m_ptr1;
    delete [] m_ptr2;
}

Have a look at the constructor CTest::CTest(), assume the first dynamic allocation succeeded for m_ptr1 and m_ptr2 failed for some reasons. Since the object is not constructed fully destructor wont be called and hence the heap allocations are not freed.

How do we overcome this problem?

One solution would be to catch the exception, free the allocated memory and then re throw the exception. Following code will show this technic.

// Constructor definition
CTest::CTest()
{
    // Init member pointers
    m_ptr1 = m_ptr2 = NULL;

    // try block
    try
    {
        m_ptr1 = new char[100]; // Assume this succeeds

        m_ptr2 = new char[100]; // Assume this fails here!

        // Other processing

        ...
    }
    // catch block
    catch(...)
    {
        // free the resources
        delete [] m_ptr1;
        delete [] m_ptr2;

        // re-throw
        throw;
    }
}

Another solution would be to use smart pointers, instead of just the raw pointers. When exception is thrown, the destructors for the local variables will be called as part of stack-unwinding which calls the destructor of the smart pointer which in turn frees the resources.

Enjoy C++!

Wednesday, 8 August 2007

Overloading "new"

In one of the previous article about operator new, we saw that it can always be overloaded.

operator new can be overloaded to define its own way of allocating memory for an object. User should be able to control the way how it allocates the memory for the object.

The global new operator is the one which invokes a call to appropriate version of operator new if its overloaded and then it will call the constructor to complete the object instantiation process.

Below is the pseudo code of what new operator does

new()
{

    // Call correct version of operator new() based on the parameters passed while initializing the object
    operator new(sizeof(CMyClass));

    // Call appropriate version of constructor
    CMyClass::CMyClass();    

}

Function operator new always has size_t as one of its parameter. The functionality of a default operator new will be as shown below,

void* operator new(size_t size)
{
    // allocate and return the pointer
    return malloc(size); 
}

Where it allocates size number of bytes and return the pointer which points to the allocated memory.

If user tries to instantiate an object of type CMyClass dynamically,

CMyClass *pObj = new CMyClass();

This will call the global new operator() function which will first call operator new(sizeof(CMyClass)) passing sizeof(CMyClass) as parameter to allocate required memory, then it will call the constructor CMyClass::CMyClass() to finish the object instantiation process.

In some cases user may want to allocate memory for an object in a predefined memory area. This can be achieved by overloading operator new().

void* operator new(size_t size, void *pMem)
{
    // just return the pre allocated memory pointer
    return pMem; 
}

User can invoke this by doing the following,

char *buf  = new char[500];                //pre-allocated buffer
CMyClass *pObj = new (buf) CMyClass();    //placement new

This will invoke the overloaded version of function operator new() which takes two parameters, first would be the size of the class and the next would be the pointer to pre-allocated buffer.

operator new(sizeof(CMyClass), buff);

And this overloaded version will just return the pointer to new operator() function which will then call the appropriate constructor.

This technic is popularly known as Placement New.

In the same way user should be able to overload operator new with different parameters.

Cheers!

Friday, 3 August 2007

Overloading const and non-const member functions

We all know about the function overloading feature in C++. Where we can have the same name given for a function with different signatures. Different signature here means different types or number of arguments for that function.

How about overloading based on constness of a member function?

Consider the scenario below,

class MyArray
{
private:
    int m_iInts[100];  // Array of integers

public:
    int& operator [](int iIndex);  // Overloading subscript operator
};

int& MyArray::operator[](int iIndex) // Definition
{
    return m_iInts[iIndex];
}

We are trying to create an integer array class, with an overloaded operator function for subscript access of the array.

we should be able to say

MyArray objArray;
objArray[10] = 100;

This will establish a call to the member function operator[](int), which returns a reference to the requested array member. It will assign a value to that particular array member.

But, consider the situation below,

void PrintArray(const MyArray &obj)
{
    // Code for printing the elements
    cout<<obj[10]<<endl;
}

Assume that this is a function for printing the array elements. This takes a constant reference to MyArray instance as parameter.

Problem is here!

When we try to print the value by saying obj[10], since the object is of constant type, it will not be able to access the non-const version of operator[](int).

Compiler complains about this saying

no operator defined which takes a left-hand operand of type 'const class MyArray'

In this situation we must declare another version of operator[](int) which will be specifically for const objects.

const int MyArray::operator[](int index) const
{
    return m_iElements[index];
}

This is a const member function - meaning not supposed to change value of any member variable.

Hence we have 2 versions of member functions with same name and even same argument but different in constness.

int& operator [](int iIndex);                 // non-const version
const int operator[](int index) const;    // const version

The first version will be used for all non-const objects and the later will be only used for const objects.

Happy coding!

Wednesday, 1 August 2007

Accessing non-static member function without object!

We know that we can call a static member function with in a class without instantiating that class. But how about a non-static member function?

Its possible too, unless we try to access any of the member variable within that function.

class CTest
{
public:
    void func()
    {
        cout<<"I can execute even without an object!"<<endl;
    }
};

int main()
{
    CTest *p = 0; // NULL pointer
    p->func();     // Calling member function

    return 0;

This compiles and works fine.

But beware! We must not try to access any of the member variables within that because this pointer will be pointing to NULL.

Remember there was an article about how a member function call is made?

Cheers!