Digging deeper into the implementation of New and Delete operators, raises couple of question as listed below.
- Under what circumstances a bad_alloc exception is thrown.
- What if there is an exception thrown inside a constructor.
- Who releases the heap memory allocated for the object, when constructor fails.
- Is it possible to reuse a chunk of memory on the heap to reconstruct the object.
- How to distinguish whether the exception is due to heap allocation error or due to a failing constructor.
Rather trying to answer these questions individually, it's better to explore compiler implementation of " new " and " delete " operators which eventually answers the above questions.
Consider CellPhone,a class declaration below
class CellPhone
{long IMEI ;
char* DeviceName ;
public:
CellPhone(int ID, char* Name)
{
IMEI = ID ;
strcpy(DeviceName,(char*)malloc(sizeof(strlen(Name)+1)));
}
void* operator new ( size_t size );
CellPhone(int ID, char* Name)
{
IMEI = ID ;
strcpy(DeviceName,(char*)malloc(sizeof(strlen(Name)+1)));
}
void* operator new ( size_t size );
void operator delete (void* buffer);
};
};
The below instruction creates an instance of this class on the heap through " new " operator.
CellPhone* PhoneObject = new CellPhone(900,"NOKIALUMIA") ;
New Operator
The "new" operator instantiates an object on the heap in two steps.
1) Allocate the required amount of memory for the object, on heap
2) Call constructor of the class to initialize the object.
Instantiating the object on heap
To allocate memory on the heap "new" operator uses a function " operator new " as shown in the class declaration. This function allocates memory specified by " size_t " parameter on heap for the object and returns a " void* " pointer. And if the memory allocation fails, run-time will throw a " bad_alloc " exception.
void* CellPhone::operator new(size_t size) throw (const char*)
{
void* buffer = malloc(size);
if(buffer = NULL) throw "Not enough memory to allocate for the object";
return buffer ;
}
The above function can be overloaded by the developer to provide custom implementations and excemption details.
Initializing the object by calling constructor
Initializing the object by calling constructor
Run-time achieves this functionality through " Placement new " operator which basically receives " void* " pointer returned by " operator new " function, allocated on the heap and calls constructor of the class to initialize the object as shown below.
Calling operator new function.
Calling operator new function.
void* buffer = operator new(sizeof(CellPhone)); // ----------->1
Typecast void* pointer to class specific pointer.
CellPhone* PhoneObject = dynamic_cast<CellPhon*>(buffer);//Simple static cast also would do.
Typecast void* pointer to class specific pointer.
CellPhone* PhoneObject = dynamic_cast<CellPhon*>(buffer);//Simple static cast also would do.
Constructing the object at the allocated space using " placement new " operator.
try
{
new(PhoneObject)CellPhone(900,"NOKIA LUMIA"); //------------> 2
}
catch(exception& e)
{
cout << e.what();
{
new(PhoneObject)CellPhone(900,"NOKIA LUMIA"); //------------> 2
}
catch(exception& e)
{
cout << e.what();
operator delete( PhoneObject );
throw "Exception inside constructor";
}
}
void CellPhon::operator delete (void* buffer)
{
free(buffer);
buffer = NULL ;
}
The above programming structure clearly explains, how the exceptions from constructor is handled. The " placement new " operator shown in instruction #2 receives pointer to the buffer allocated as shown in instruction #1 and tries to construct the object at that location.
During this process if there is any exception thrown inside the constructor it is caught and the allocated memory is released back to heap using " operator delete ( ) " function, which is a compliment of " operator new ( ) " function.
With the above implementation user would be clearly able to distinguish whether the " new " operator failed due to "heap allocation error " or due to " exception thrown " inside the constructor.
I hope this article was helpful in demystify obscure implementation details of "New" and "Delete" operators. Suggestions and comments if any is appreciated.
I hope this article was helpful in demystify obscure implementation details of "New" and "Delete" operators. Suggestions and comments if any is appreciated.