Monday, 29 June 2009

The case for 'virtual destructor'

You may often find that the destructor of your class is virtual. The main reason for having virtual destructor stems from the fact that some other class may derive from your class. If the derived object is referenced as base object and destroyed then the derived class objects wont be deleted. To overcome this problem we define the destructor virtual . Lets look at an example:


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Example showing the need for Virtual Destructor
#include <iostream>

using namespace
std;

class
Base
{

public
:
Base() {
cout<<"Base Constructor Called"<<endl;
}
~
Base() {
cout<<"Base Destructor Called"<<endl;
}
};


class
Derived : public Base
{

public
:
Derived() {
cout<<"Derived Constructor Called"<<endl;
}
~
Derived() {
cout<<"Derived Destructor Called"<<endl;
}
};


int
main()
{

cout<<"\nTESTING NON-VIRTUAL BASE DESTRUCTOR\n";
Base *b = new (Derived);
delete
(b);
return
0;
}


The output is as follows:

Now lets modify the base destructor to make it virtual.


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Example showing the need for Virtual Destructor
#include <iostream>

using namespace
std;

class
Base
{

public
:
Base() {
cout<<"Base Constructor Called"<<endl;
}

virtual
~Base() {
cout<<"Base Destructor Called"<<endl;
}
};


class
Derived : public Base
{

public
:
Derived() {
cout<<"Derived Constructor Called"<<endl;
}
~
Derived() {
cout<<"Derived Destructor Called"<<endl;
}
};


int
main()
{

cout<<"\nTESTING VIRTUAL BASE DESTRUCTOR\n";
Base *b = new (Derived);
delete
(b);
return
0;
}



The modified output is as follows:


There is one more point to be noted regarding virtual destructor. We can't declare pure virtual destructor. Even if a virtual destructor is declared as pure, it will have to implement an empty body (at least) for the destructor.

You can read more about this at C++ FAQ.

Monday, 22 June 2009

An example of dynamic_cast

Lets look at an example of dynamic_cast where you can cast a pointer from Derived class to Base class. The example should be self explanatory:


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//A very simple program to explain dynamic cast

#include <iostream>

using namespace
std;

//Base class
class A
{

public
:
int
a;
int
b;
private
:
int
c;
};


//Derived class
class B :public A
{

private
:
int
d;
};


//function that prints a and b
void function(A a)
{

cout<<"\n a = "<<a.a<<" b = "<<a.b<<endl;
}


int
main()
{

A *a;
B *b=new(B);
b->a = 20, b->b = 40;
a = dynamic_cast<A*>(b); //Dynamic cast from Dervied to Base
function(*a);
return
0;
}



The output is as follows:

Thursday, 18 June 2009

Copy Constructor and Assignment Operator

This example shows the Copy Constructor and the Assignment Operator. In the example, I have just relied on the Default Copy Constructor and the Default Assignment Operator. For a complex class, the default may not be a good option and they will have to be explicitly written.


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include<iostream>

using namespace
std;

class
A {
public
:
int
x,y;
};


int
main()
{

A a;
a.x = 11;
a.y = 2222;

A a2(a); //Default Copy constructor called
//Copies a paramaters to a2
cout<<"a2 variables are: a2.x = "<<a2.x<<" and a2.y = "<<a2.y<<endl;

A a3;
a3 = a; //Default Assignment Operator called
//Copies a paramaters to a3
cout<<"a3 variables are: a3.x = "<<a3.x<<" and a3.y = "<<a3.y<<endl;

return
0;
}



The output is as follows:

Wednesday, 17 June 2009

Initialising Arrays while doing 'new'

The example below shows how to initialise the array when you are dynamically alocating the memory with new:


//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
#include<iostream>

using namespace
std;

int
main()
{

//int* x = new int(10); - Common Bug for Array allocation
int *x = new int[5]; // Memory UnInitialised
int *y = new int[5]();

for
(int i = 0; i < 5; i++)
{

cout<<"x["<<i<<"]="<<x[0]<<endl;
cout<<"y["<<i<<"]="<<y[0]<<endl;
}


//delete x; - Another Common bug
delete[] x;
delete
[] y;
return
0;
}



The output is as follows:

Monday, 15 June 2009

Avoiding Redifinition using #pragma once

Lets write a very simple program where there is main.cpp that includes classA.h and classB.h. classA.h contains class A and classB.h contains class B.



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Program to show how to avoid redifinition problems
#include <iostream>
#include "classA.h"
#include "classB.h"

using namespace
std;

int
main()
{

A a;
B b;
a.a = 20; //some stuff not relevant here
b.a = 40; //some stuff not relevant here
return 0;
}

//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//A very simple example class that does nothing
class A
{

public
:
int
a;
int
b;
private
:
int
c;
};
//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//A very simple example class that does nothing
#include "classA.h"

class
B :public A
{

private
:
int
d;
};

When we try to compile this, the compiler complains as follows:




To get round this problem, in each of the include file we can use a #define as follows

#ifndef _CLASSA_H_

#define _CLASSA_H

//Some code

#endif //_CLASSA_H

In C++ we can also write #pragma once. Using #pragma once can increase compilation speed and the compilor may optimise the code as the use of pre-processor can be removed. So the class A in our program giving problem can now be modified as follows for the program to compile properly:




//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//A very simple example class that does nothing
#pragma once
class A
{

public
:
int
a;
int
b;
private
:
int
c;
};


Wednesday, 10 June 2009

What can you do in C++ which you cant do in C

Is there anything you can do in C++ that you cannot do in C?

No. There is nothing you can do in C++ that you cannot do in C. After all you can write a C++ compiler in C.

Difference between MyClass p; and MyClass p();

Sometimes there are interesting questions asken in an interview. I am going to add some of them when I come across under the 'Interview Questions' tag.

So, what is the difference between MyClass p; and MyClass p();?

MyClass p; creates an instance of class MyClass by calling a constructor for MyClass.

MyClass p(); declares function p which takes no parameters and returns an object of class MyClass by value.

Monday, 8 June 2009

The problem with Maps in C++

The following discussion is from More Exceptional C++ By Herb Sutter:

Question 1:
a: What's wrong with the following code? How would you correct it?

map::iterator i = m.find( 13 );
if( i != m.end() )
{
const_cast( i->first ) = 9999999;
}

b: To what extent are the problems fixed by writing the following instead?

map::iterator i = m.find( 13 );
if( i != m.end() )
{
string s = i->second;
m.erase( i );
m.insert( make_pair( 9999999, s ) );
}

Consider a map named m that has the contents shown in Figure; each node within m is shown as a pair. I'm showing the internal structure as a binary tree because this is what all current standard library implementations actually use.

As the keys are inserted, the tree's structure is maintained and balanced such that a normal inorder traversal visits the keys in the usual less ordering. So far, so good.

But now say that, through an iterator, we could arbitrarily change the second entry's key, using code that looks something like the following:

1. a) What's wrong with the following code? How would you correct it?

// Example: Wrong way to change a

// key in a map m.

//

map::iterator i = m.find( 13 );

if( i != m.end() )

{

const_cast( i->first ) = 9999999; // oops!

}

Note that we have to cast away const to get this code to compile. The problem here is that the code interferes with the map's internal representation by changing the map's internals in a way that the map isn't expecting and can't deal with.

Example above corrupts the map's internal structure (see Figure). Now, for example, an iterator traversal will not return the contents of the map in key order, as it should. For example, a search for key 144 will probably fail, even though the key exists in the map. In general, the container is no longer in a consistent or usable state. Note that it is not feasible to require the map to automatically defend itself against such illicit usage, because it can't even detect this kind of change when it occurs. In Example above, the change was made through a reference into the container, without calling any map member functions.

A better, but still insufficient, solution is to follow this discipline: To change a key, remove it and reinsert it. For example:

b) To what extent are the problems fixed by writing the following instead?

// Example: Better way to change a key

// in a map m.

//

map::iterator i = m.find( 13 );

if( i != m.end() )

{

string s = i->second;

m.erase( i );

m.insert( make_pair( 9999999, s ) ); // OK

}

This is better, because it avoids any change to keys, even keys with mutable members that are significant in the ordering. It even works with our specific example. So this must be the solution, right?

Unfortunately, it's still not enough in the general case, because keys can still be changed while they are in the container. "What?" one might ask. "How can keys be changed while they're in the container, if we adopt the discipline of never changing key objects directly?" Here are two counterexamples:

Let's say the Key type has some externally available state that other code can get at—for example, a pointer to a shared buffer that can be modified by other parts of the system without going through the Key object. Let's also say that that externally available state participates in the comparison performed by Compare. Then making a change in the externally available state, even without the knowledge of the Key object and without the knowledge of the code that uses the associative container, can still change the relative ordering of keys. So in this case, even if the code owning the container tries to follow an erase-then-reinsert discipline, a key ordering change can happen at any time somewhere else and therefore without an erase-then-reinsert operation.

Consider a Key type of string and a Compare type that interprets the key as a file name and compares the contents of the files. It's obvious that even if the keys are never changed, the relative ordering of keys can still change if the files are modified by another process, or (if the file is shared on a network) even by a user on a different machine on the other side of the world.

For details see Item 8 of the book More Exceptional C++ By Herb Sutter



Monday, 1 June 2009

A look at Smart Pointers

There is lot of confucion, misconceptions and misunderstanding regarding smart pointers. After looking at various books and tutorials, i got quite confused till I managed to figure out what they exactly are:

Smart pointers are objects that look and feel like pointers, but are smarter.

To look and feel like pointers, smart pointers need to have the same interface that pointers do: they need to support pointer operations like dereferencing (operator *) and indirection (operator ->). An object that looks and feels like something else is called a proxy object, or just proxy.

To be smarter than regular pointers, smart pointers need to do things that regular pointers don't. What could these things be? Probably the most common bugs in C++ (and C) are related to pointers and memory management: dangling pointers, memory leaks, allocation failures and other joys. Having a smart pointer take care of these things.

The simplest example of a smart pointer is auto_ptr, which is included in the standard C++ library. You can find it in the header , or take a look at Scott Meyers' auto_ptr implementation. Here is part of auto_ptr's implementation, to illustrate what it does:

template <class T> class auto_ptr
{

T* ptr;
public
:
explicit
auto_ptr(T* p = 0) : ptr(p) {}
~
auto_ptr() {delete ptr;}
T& operator*() {return *ptr;}
T* operator->() {return ptr;}
// ...
};

As you can see, auto_ptr is a simple wrapper around a regular pointer. It forwards all meaningful operations to this pointer (dereferencing and indirection). Its smartness in the destructor: the destructor takes care of deleting the pointer.

Lets look at a proper example:

#include<iostream>
#include<memory>


using namespace
std;

class
A
{

public
:
int
*data;
string name;
A(string n): name(n)
{

cout<<"Constructor of A = "<<name.c_str()<<" called "<<endl;
data = new(int);
};

A(string n, int x): name(n)
{

cout<<"Overloaded Constructor of A = "<<name.c_str()<<" called "<<endl;
data = new(int);
*
data = x;
};
~
A()
{

cout<<"Destructor of A = "<<name.c_str()<<" called "<<endl;
delete
(data);
data = this->data;
data = NULL;
}

A* operator ->() { return this;};
};


void
someFunc()
{

auto_ptr<A> a1(new A("a1"));
cout<<"Enter a number and press enter: ";
cin >> (*a1->data);
cout << "a1->data = "<<*a1->data<<endl;

A a2("a2",25);
A *a3 = new A("a3");
}


int
main()
{

cout<<"Before SomeFunc()"<<endl;
someFunc();
cout<<"After SomeFunc()"<<endl;
return
0;
}
The output is as follows:


As you have probably noticed, the instance a3 is never deleted and will cause memory leaks. Using smart pointer would automatically delete the instance a3 and the memory associated with it.

You can read Smart Pointers in much more detail at the References below.

References:
http://ootips.org/yonat/4dev/smart-pointers.html
http://www.geekpedia.com/tutorial47_Smart-Pointers---Part-1.html
http://www.geekpedia.com/tutorial59_Smart-Pointers---Part-II.html