C++ Blog

Monday, April 16, 2007

When "constructor initializer list" is mandatory?

1) To initialize const data member
2) To initialize reference data member
3) To call a non-default constructor in base class
4) To call a non-default constructor for a member object

For example

class Game {
GameBoard gb;
// Composition
public:
// Default GameBoard constructor called:
Game() { cout << "Game()\n"; }
// You must explicitly call the GameBoard
// copy-constructor or the default constructor
// is automatically called instead:
Game(const Game& g) : gb(g.gb) { cout << "Game(const Game&)\n"; }
Game(int) { cout << "Game(int)\n"; }
Game& operator=(const Game& g) {
// You must explicitly call the GameBoard
// assignment operator or no assignment at
// all happens for gb!
gb = g.gb;
cout << "Game::operator=()\n";
return *this;
}
};

****** Code sample taken from Thinking in C++ by Bruce Eckel **********

When "Copy Constructor" is invoked?

1) When an object is created from an existing object
2) When an object is passed by value
3) When an object is returned by value

Tuesday, April 03, 2007

Explicitly calling destructor?

If the object is created on the stack then destructor will be called but when the object goes out of scope the destructor is called again.With the object on heap(created with new operator) the destructor will be executed but the memory won't be released.
So explicitly call the destructor for a object only when that object is created with the "placement" new operator, because here you don't want to release the memory but still you want to execute destructor to release all the resources holded by it.

How to call a destructor?

To call the destructor manually use the following syntax
ClassA ObjA;
ObjA.~A();

The following are incorrect
~ObjA(); // This might call complement operator for an object
~ClassA(); // This creates temporary object and applies complement to it

Monday, April 02, 2007

"GARBAGE COLLECTOR" a Curse or a Bless?

What is "Manual Memory Management"?
In the manual memory management the user himself should take care of allocating memory for objects and releasing the memory when its not needed anymore. C++ supports manual memory management because it doesn't have any mechanism which collects memory automatically when it is not needed.

What is "Garbage Collector"?
Garbage collector is automated way doing memory management. In this case the user needs to allocate memory but he doesn't need to worry about the re-claiming memory becaues garbage collector does that automatically. C# and Java falls under this category.

Manual Memory Management
A Bless

1) We don't need to keep track of all active objects or periodically look for memory which can be re-claimed. (This is needed for Garbage Collector)
2) More control over memory allocation and de-allocation. You can reclaim memory when ever needed by using a "delete" operator. Which in turn calls the destructor so we can be sure that object releases all the resources before it is destroyed.

A Curse

1) Main problem with this approach is "Memory Leak" which degrades system performance and may lead to fatal errors. Failing to release allocated memory will result in memory leak.
2) Releasing memory which are pointed by other objects will result in a undefined behaviour when the other object tries to access its data. This is called as "Dangling Pointer"
3) Trying to release the same memory twice unknowingly can lead to serious error.


Garbage Collector
A Bless

1) It is very simple and safe. Simple in the sense the user doesn't need to worry about releasing object and keep track of all the objects. Safe because you don't need to release memory explicitly so you may not get in to situation of releasing same memory twice or releasing memory which is pointed by some other reference.

A Curse

1) Garbage collector needs CPU cycles for re-claiming all the unused memory. It also needs to keep track of all the objects that are in use with a datastructure or it needs to scan through the memory for finding it.
2) It makes calling the object destructor non-deterministic because of no control over the memory when it will be released. The memory is released only when the garbage collector runs and recyles the object. But it is not easy to predict when the garbage collector will run. In some systems it will start when the free memory limit threshold is reached, in some systems it is started when the CPU cycles are free.
3) Real-time applications can't use garbage collectors since allocating of CPU cycles to garbage collector could cause an event to be missed :-(.


As we can see the curse of Garbage collector is more than its blessings but this often overcomes in most of the programs, using garbage collector is a trade-off but most of the modern systems its a bless.

C++ is a mixed blessing, since you have to do manual memory management but you can also write code to do garbage collection with the power of C++.
Ref:

When "new" fails?

When you create a object with new it allocates required memory for object, calls the constructor and returns a pointer to the created object.
If it fails to allocate contiguos memory, it calls a special pre-defined function called "new_handler" function, the default functionality of the function is to throw an exception, it throws an bad_alloc exception.
The user can override the defaul new_handler function using a "set_new_handler" function defined in new.h header file. The new handler function should take no arguments and return a void.

What if, I overload "new" operator?
When the user overloads the new operator it doesn't call new_handler by default. It is tied to the default behaviour of new operator, so when the user over loads the new the user should take care of calling this function.


What I can do in new-handler?
  • The user can write code to log and error message about the memory could not be allocated and then throw error, so that it might give enough ninformation to debug the program.
  • Even we can write a "garbage collector" in that function and try to re-claim the memory.


#include <iostream>
#include <new>
using namespace std;
int count = 0;
void out_of_memory()
{
cerr << "memory exhausted after " <<>
exit(1);
}
int main() {
set_new_handler(out_of_memory);
while(1) { count++; new int[1000]; // Exhausts memory }
} ///:~
********** Code sample from Thinking in C++ by Bruce Eckel *************

"delete" operator in C++

1) delete calls the destructor for an object before it deallocates the memory.

2) delete should be called for objects that are constructed with new only, if it is used for the object that was allocated with malloc then the result is undefined.

3) delete should be called only for dynamically allocated objects should not be used for the objects in stack if it is used then the result is undefined.

4) Deleting array of objects should be used as delete[] ptr or if it used like delete ptr; it deletes only the first object and the remaining elements are not deallocated.
For example;
student *obj = new student[10];
...
...
...
delete []obj; // This is correct way to delete. delete obj; will result in deleting obj[0] alone.

5) Deleting an object twice using delete is not recommended and the result it un-defined.
For example;
student *obj = new student();
....
delete obj;
....
...
delete obj; // The result is undefined because the previous delete doesn't gurantee storing 0 in the obj.

6) deleting a object pointer with value 0 wont result an error.
For example;
student *obj = new student();
....
delete obj;
obj = 0;
...
delete obj; // This is ok because obj has 0