Tuesday, 4 September 2007

Global vs Member overloaded operator new

In an earlier post we saw how to overload operator new, which will allow us to have customized memory allocation for an object on heap.

Its possible to place this overloaded operator new function either globally or as member function within a class.

 

// Global overloaded operator new
void *operator new(size_t size)
{
    return malloc(size);
}

 

// Class CTest
class CTest
{
public:

    // Member overloaded operator new
    void *operator new(size_t size)
    {
        return malloc(size);
    }

};

 

Is there any behavioral difference between these two versions of operator new?

Yes, there is.

If we have overloaded new as a member function within a class, it will always have high precedence over the globally defined version.

If we have a globally defined operator new function, the same will be used for all classes which doesn't have overloaded operator new defined within.

If both exist, the member version will be preferred over the global version.

Is there any advantage of this feature?

Yes.

Global version of overloaded operator new will be very much useful when we need to have a common strategy for memory allocation for all the classes in the module.

If we are in a situation where we need to have a specific way for allocation for a particular class which is different from others then we can overload operator new for the class with desired allocation method. A good example would be to allocate and initialize the allocated memory with zeros.

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!

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

Saturday, 30 June 2007

Library - Reusable binary component

In our daily development activities, we will come across various types of libraries. Like Static Library, Dynamic Linked Library, Plugins etc,


In this article, I have tried to explain each of these.


You consider any type of library, final objective will remain the same - Binary Reusability.


Developer should identify a set of re-usable components or routines in his module and create a library. So that, this can be distributed and used by anyone instead of rewriting the components again.


Lets start from Static Library(.lib) (called as Archive in unix world). Usually libraries will be create with .lib extension (.a in unix). The idea behind static library is to create a reusable binary module that can be linked with any executable or another dynamic library, so that it can reuse the static library components. Linking/Binding module will have the responsibility of linking your executable with the static library. Hence the final size of the executable will be original executable code size + the static library code size. The executable will embed the static library within.




All the routines and components which were present in the static library can be directly used as if they were implemented in the same module.


After compilation, at link time the linker module will look for all the symbols which were referenced in the executable and tries to link the static library. The developer has to specify the static library so that the linker can link it with the executable.



Dynamically Linked Library (DLL): Generally we export functions or routines from DLLs. When we say export that means those are all the entry points for the executables that are linked with it. Only the exported functions can be accessed by the executables.


We can use the DLLs in two ways. One way is to link the static interface of a DLL with an executable and another is to load the DLL at run-time. Both have its own advantages.


Statically linking the DLL interface : For any DLL, there will always be a static library(.lib) generated. This static library is just an interface to the DLLs exported functions, they wont have any definitions for the exported functions. They are just like routers to the actual definition which is present in the DLL.


Executables can link to this static library and use the exported functions in the DLL. The executable will just have DLLs interface embedded in it. DLL will be a separate module which will be loaded by the loader when we start the executable.






In this method, the DLL will be loaded when we start the executable. The life span of the exe along with the DLL can be depicted as below,



Loading a DLL at Run-time : This is the second way of using a DLL. Where we can use certain System API's to load the DLL at run-time. The static interface for the DLL is not used in this case. A typical example is shown below.



// Load the library
MyDll = LoadLibrary("C:\\MyWork\\aDll.dll");

// Get address of exported function
FuncPointer = GetProcAddress(MyDll, "SomeExportedFunc");

// Make call
FuncPointer();

// Release the library
FreeLibrary(MyDll)


Note here that, the DLL can be loaded and released at any point of time with in the life span of the exe. Which is different from the previous method where it would load it at the start of the execution itself.


A Plugin is an extension to this method. Lets talk about this in further articles.

Cheers!

Friday, 29 June 2007

Can access a private function?

Today, at lunch time, Anand had a slip in his hand with C++ code written on it. He was smiling showing that to me and asking to tell how the code behaves.

As usual he had a great feeling of discovering some new thing ;)

I had to watch the code, it goes like below

Class CBase
{
    public:
        virtual void vfunc()
        {
            // Some definition
        }
};

 

Class CDerived : public CBase
{
    private:
        void vfunc()
        {
            // Some definition
        }
};

 

int main()
{
    CBase *pBase = new CDerived();
    pBase->vfunc();
}

CBase has a virtual function vfunc which is overridden in CDerived. In the main routine we are making a base pointer to point to the derived class instance. Then we are calling the vfunc.

The main point to note here is - CDerived::vfunc() is private.

Even the function is declared as private its accessible! when we do

pBase->vfunc();

Strange!

This is because the real call to the function is made thru virtual pointer.

We wouldn't be able to access the same function via an instance of CDerived. Isn't it?

What to say about this? Is this a design flaw? A loop hole? or just say "This is what C++ is"!

Sunday, 24 June 2007

dynamic_cast

Lets talk about Dynamic Casting today!

dynamic_cast is one of the four C++ casting operators (static_cast, dynamic_cast, reinterpret_cast and const_cast), extensively used in case of polymorphic types.

Unlike C type casting which does a static type check, this will do a type check at run time. If the casting is invalid, it either throws bad_cast exception or returns a NULL pointer.

This has to be used for safe run-time down casting.

What is Down casting?

Casting a superclass pointer (or reference) into a pointer (or reference) to a subclass in a class hierarchy is said to be down casting.

Typical example looks like this,


CDerived *pD = dynamic_cast<CDerived *>pB;


When to use?

Consider the scenario below,



Where the CControlIface is an abstract base class with a pure virtual function Draw(). There are two concrete classes implementing the CControlIface interface, CButtonControl and CTextControl which overrides the Draw()'s implementation. Also, they have their own methods


CButtonControl::OnClick()
CTextControl::OnKeyTyped()


The problem is how will we identify the type of object pointed at run-time, if we just have the base class pointer or reference?

The solution is dynamic_casting

Let's look into some code.


CControlIface *pControl1 = new CButtonControl();
CControlIface *pControl2 = new CTextControl();

...
...

ProcessButtonEvent(pControl1);
// No idea what pControl1 points to, at compile time

...
...

void ProcessButtonEvent(CControlIface *pControl)
{
    // Here we need make sure safe down-cast happens
    CButtonControl *pButton = dynamic_cast <CButtonControl *> pControl;

    // casting works fine here since we had passed pControl1

    ...

    if(pButton != NULL)
    {
        pButton->OnClick();
        // We can now safely call OnClick() of CButtonControl
    }
}


What would have happened if we had passed pControl2 while calling ProcessButtonEvent()?

dynamic_cast would have failed since pControl2 is not pointing to CButtonControl's instance. This check is performed by dynamic_cast operator at run-time using RTTI (Run-time Type Information).

Dynamic casting allows us to perform safe type conversions and lets our programs take appropriate actions when such casts fail.

Cheers!

 

Sunday, 17 June 2007

What's "new"?

Today's article talks about the new, which is an essential operator in C++ for dynamically instantiating an object.

Why do we need new operator?
There's a lot of difference between C's malloc and new. It does more than just allocating memory. It also calls the constructor. Which facilitates to initiate the object.

Believe me, operator new and new operator are completely different!
When we instantiate an object
CTest *pObj = new CTest();

This calls global new operator which performs 2 main tasks
1. Call operator new for allocating memory.
2. Call constructor of the particular object.

We can always overload operator new which performs memory allocation operations. But we cannot change the meaning of the global new operator.

Typical example where we overload operator new will be in case of placement new where we change the actual meaning of operator new by passing address of memory where it has to instantiate the object.

Let's talk about placement new in forth coming articles.

Tuesday, 12 June 2007

Conceptual "Virtual Constructors"

In one of my old article I had said that we cannot make the constructors virtual.

But its possible to have Conceptual Conceptual "Virtual Constructors". You might be wondering what do I mean by conceptual here?

Consider following code snippet,


class CAccountIface
{

};

class CSavingsAccount : public CAccountIface
{

};

class CCreditAccount : public CAccountIface
{

};

 


And I have one more class which will have a list of accounts


class CBank
{
    public:
        CAccountIface* CreateAccount(int iAccType);
        std::vector<CAccountIface *> m_Accounts;
}


 Here the member function CAccountIface* CBank:: CreateAccount(int iAccType) acts like a virtual constructor. Depending on the type the user passes either the constructor for CSavingsAccount or CCreditAccount will be called and respective object will be instantiated. This behaves like a virtual constructor.


We can even establish virtualism in case of copy constructors.

Let's try writing a copy c'tor for CBank class.


CBank::CBank(const CBank &AnotherBank)
{

    for(std::vector<CAccountIface *>::size_type i = 0; i < AnotherBank.m_Accounts.size(); ++i )
    {
        this->m_Accounts[i] = AnotherBank.m_Accounts[i]->Clone();
    }
}


I guess u'll already be wondering about the implementation for clone() member function.

Clone() has to be a pure virtual function in CAccountIface, and we can override this in CSavingsAccount and CCreditAccount to clone itself.

So the updated code will be as shown below,


class CAccountIface
{
    public:
        virtual CAccountIface *Clone() = 0;
};

class CSavingsAccount : public CAccountIface
{
    public:
        virtual CSavingsAccount *Clone(){ return new CSavingsAccount(*this);}

};

class CCreditAccount : public CAccountIface
{
    public:
        virtual CCreditAccount *Clone(){ return new CCreditAccount(*this);}

};


When we say


m_Accounts[i]->Clone();


The Clone() function will be called based on the type of object pointed by the pointer m_Accounts[i].

This concept is also referred to as "Factory Pattern"

Saturday, 2 June 2007

Static & Dynamic memory allocations...

I thought of writing this article since it was quite interesting even though it sounds as basic and primitive.

Last night when I was coming back to home on Company's shuttle, my mate Debendra had few C++ questions for me.

He asked "If I create a variable on stack say, int i; and if I say char *p = new char;. When will be the memory gets allocated? What time? Is it run-time or compilation time?"

I had to say "All allocations happen only when you run the program, compiler will just compile the C++ code to instructions which will allocate the memory required on heap/stack"

Then I got an unexpected question from him - "Then why do we say int i; as static allocation and char * p = new char as dynamic allocation, even though all allocations are happening at run-time?"

A crazy question!

Such a primitive and basic doubt every one may get and get confused.

All allocations whether it may be dynamic or static happens at run-time only. But how the allocation is done matters.

Let’s take the static allocation,

int i;

when compiler compiles this code, compiler knows what the size of int is and it knows what number of bytes needs to be allocate at compilation time only. It generates instructions to allocate those many bytes, so that at run-time those many bytes are allocated.

In case of dynamic allocation,

char *p = new char(n);

Compiler wont have any idea what is n, it may be a function parameter or a value evaluated by an expression or even it can be a constant value, but at compilation time it has no idea what may be the number of bytes allocated. This can be dynamically configured and controlled at run-time.

Importantly, in case of dynamic allocation, the amount of memory allocated is determined by the program at the time of allocation and need not be known in advance.

Hence we say this as dynamic allocation.

Hope Debendra had got his doubt cleared.

Thursday, 31 May 2007

Const Correctness

I recently found a good article by Herb Sutter on Const-Correctness, a powerful feature of C++. This article talks about when to use const and when not to use it.

Const Correctness by Herb Sutter

Very interesting!

Thursday, 24 May 2007

Resolving function address ...

The question is, if we are calling a function 'void function()' from 'main()', how the call is actually made?

We know the answer, it will be just a jump instruction to a particular address where the function instruction set starts.

How the member function address resolved in C++?

We all know member function is not stored as part of the class. It will be stored outside somewhere (code segment?). Then how is the call made when we say 'obj.function()'?

The answer is simple, actual call made would be like 'function(&obj)'. Thereby it will be just a simple jump instruction as we saw earlier.

Wednesday, 14 March 2007

Calling ctor!!

Well, suppose we have a class as below


class CTest
{
    public:
        CTest()
        {
            cout<<"ctor called!";
        }
};

int main()
{
    CTest();
}


Does it mean c'tor can be called without creating an object?

Nope!! ofcourse not!!

The reason is when CTest(); is called, the compiler inserts the code to create a tempory object of CTest and calls its c'tor. Also it destroys the object right after executing CTest(); statement.

That is the reason calling constructor inside another constructor is not valid.

Tuesday, 16 January 2007

delete this;

"delete this;" legal?

Yes! of course its legal, with certain restrictions.

Once you call 'delete this;' no member variables should be accessed, since they would have been deleted already.


class CTest
{
    int iInt;
    char *iStr;

    public:
        void func()
        {
            ...

            delete this; // object destroyed here

            ...

            iInt = 6;// Illegal! don't do this
        }
};


Also this is not valid if the object is created on stack. Following should not be done.


CTest obj;
obj.func(); // Not valid since obj is on stack

 

CTest *ptr = new CTest();
ptr->func();


// Valid, only if no members are accessed after delete this;


 


One more interesting fact! What if we use 'delete this;' in destructor? ;)
Of course it will create the recursion calls to destructor!!!


 

Is there any practical use of this then?

Yes!

Consider the scenario where I would want to restrict the user to be able to create an object only on heap. User should not be able to create the object on stack.

We can achieve this by making destructor private. There by preventing the stack unwinding to happen, which will intern avoid creating variables on stack. Then the user will only be able to create object on heap.


class COnlyOnHeap
{
    private:
        ~COnlyOnHeap(); // destructor made private
};

COnlyOnHeap obj; // Not possible since d'tor is private.
COnlyOnHeap *ptr= new COnlyOnHeap(); // Possible


We achieved our goal!


Object can only be created on heap but not on stack.


But, Wait!

How will u cleanup this?


We cannot say "delete ptr", because d'tor is private.


How will we cleanup this then?


The only way is to expose one more cleanup public function which does "delete this;"!



COnlyOnHeap::Cleanup()
{
    delete this; // This calls the private d'tor within the class
}


Enjoy C++

 

Implementing a "final" class in C++

The key word "final" exists in java world. It means, no class can inherit from the class declared as "final". A class which cannot be inherited further.

The simple method by which we can achieve this is to make the constructor of the class private.


class CFinal
{
    private:
        CFinal(); // Private constructor to avoid inheritance

    public:
        static CFinal *GetInstance();


       // static public member function to create the instance
};


This method looks very simple. If we try to derive another class from CFinal and try to instantiate that class, compiler errors out saying cant access CFinal's constructor, since its private.

But, this method has its own drawbacks,


  • Need to have a static public member function to create instance.

  • If the class needs to have more than one type of c'tors, all these c'tors need to be replaced by corresponding version of static-public-member function.

  • Object cannot be instantiated on stack.

What if we make destructor private, instead of c'tors?
We can achieve the "final" thing.
But, this too cannot be instantiated on stack (stack-unwinding needs d'tors to be public).


We can club private d'tors, private c'tors, friend-class and virtual inheritance concepts to achieve a good solution.


class CFinal;  // Forward declaration

class CFinalLocker
{
    private:
        CFinalLocker();
        ~CFinalLocker();

    friend class CFinal;
};

class CFinal : public virtual CFinalLocker
{
    ...
};

class CDerived : public CFinal
{
    ...
}

CFinal objFinal; //OK - no problem
CDerived objDer; // Error! - Cant access CFinalLocker's c'tor


Following is the useful explanation of the above technique


  • CFinalLocker which is the base class for CFinal will have all of its c’tors and the destructor private.

  • CFinal has been made friend of CFinalLocker. This is to facilitate CFinal to access all the members of CFinalLocker including members which are private. This will allow us to instantiate CFinal.

  • We inherit our CFinal virtually from CFinalLocker. Now whenever anyone attempts to inherit class from CFinal and try to instantiate it, then its constructor tries to call the constructor of CFinalLocker. But the constructor of Temp is private so compiler complains about this and it gives error during the compilation, because your derived class is not friend of CFinalLocker. Remember friendship is not inherited in the derived class.

  • The purpose of inheriting CFinal virtually from CFinalLocker : the object of most derived class (whose object is created) directly calls the constructor of virtual base class (to avoid diamond problem). Now the most derived class (Bottom in case of diamond problem) directly calls the most base class (Top in diamond problem) constructor. So when we try instantiating CDerived compiler errors out since the c’tor in CFinalLocker is private.

Friday, 12 January 2007

Thursday, 11 January 2007

Why can't we have "Virtual Constructors"?

Virtual mechanism acts on 'complete objects'.
An object is complete 'after' the constructor has finished executing.
So, it is illegal to make constructors virtual.
Destructors can be virtual because by the time you apply them object has been constructed completely.

Need for "Virtual Destructor"

If we have 2 classes, say

class CBase{
public:
CBase(){}
~CBase(){}
};

class CDerived : public CBase{
public:
CDerived(){}
~CDerived(){}
};

and if we do,

CBase* pBase = new CDerived;
delete pBase;

Since CBase does not have a virtual destructor, the delete pBase invokes the destructor of the class of the pointer (CBase::~CBase()), rather than the destructor of the most derived type (CDerived::~CDerived()). And as you can see, this is the wrong thing to do in the above scenario.

A class must have a virtual destructor if it meets both of the following criteria:

  • You do a delete pBase.
  • pBase actually points to a derived class object.

Assignment operator Vs. Copy constructor

The copy constructor is for creating a new object. It copies a existing object to a newly constructed object.

The assignment operator is to deal with an already existing object.


class MyObject
{
    public:

        MyObject(); // Default constructor
        MyObject(MyObject const & a); // Copy constructor

        // Assignment operator
        MyObject & operator = (MyObject const & a)
};


The copy constructors play an important role, as they are called when class objects are passed by value, returned by value, or thrown as an exception.


// A function declaration with an argument of type MyObject,
// passed by value, and returning a MyObject

MyObject f(MyObject x)
{
    MyObject r;
    ...
    return(r); // Copy constructor is called here
}

// Calling the function :

MyObject a;

f(a); // Copy constructor called for "a"


It should be noted that the C++ syntax is ambiguous for the assignment operator.


MyObject x; x=y;


and


MyObject x=y;


have different meaning.


MyObject a; // default constructor call

MyObject b(a); // copy constructor call

MyObject bb = a; // identical to bb(a) : copy constructor call

MyObject c; // default constructor call

c = a; // assignment operator call

 

Overloading Vs. Overriding

  • Overloading is nothing but static binding.

  • Overriding is dynamic binding which will be resolved at run-time.

  •  



  • Overloading deals with multiple methods in the same class with the same name but different signatures.

  • Overriding deals with two methods, one in a parent class and one in a child class, that have the same signature.

  •  



  • Overloading lets you define a similar operation in different ways for different data.

  • Overriding lets you define a similar operation in different ways for different object types.

  •