Overloading new and delete in global scope is a very extreme approach, this should not be done till it is sure that the global versions of new and delete are not good for the whole system.
Arguments of new:
The overloaded new operator takes an argument of type size_t. This represents number of bytes in object. The compiler generates this argument secretly and passes this to new function as the first argument. This argument represents the size of the object. The overloaded new function returns either a pointer to the allocated object of given size or it returns zero bytes. Zero bytes are return when new function cannot allocate the memory (in such case, even the constructor will not called!). When such error occurs, then the overloaded new function, may also throw an exception. This exception will indicate that there was an error and some catch block will handle.
Return type of new
The operator new return a return value which has type void*. It does not return a pointer to any particular type. This function only allocates the requested size of memory, and do not a construct the object. The compiler will ensure that it calls the proper constructor.
Argument of delete
The operator delete takes parameter (of type void*) representing memory address that was allocated by operator new. The type of argument is void* because the object no longer exits. Actually, the compiler already has called the destructor and now this is only a chunk of memory.
Return type of delete
The return type is void.
#include <iostream>
using namespace std;
void* operator new(size_t sz)
{
cout << "operator new: size="
<< sz
<< " Bytes"
<< endl;;
void* m = malloc(sz);
if(!m) cout << "no memory allocated"
<< endl;
return m;
}
void operator delete(void* m)
{
cout << "operator delete"
<< endl;;
free(m);
}
class S
{
int i[100];
public:
S() { cout << "S::S()" << endl;; }
~S() { cout << "S::~S()" << endl; }
};
int main() {
cout << "\nCreating & destroying int"
<< endl;
int* p = new int(47);
delete p;
cout << "\nCreating & destroying a class"
<< endl;
S* s = new S;
delete s;
cout << "\nCreating & destroying array of class"
<< endl;
S* sa = new S[3];
delete []sa;
}
The output is :
Creating & destroying int
operator new: size=4 Bytes
operator delete
Creating & destroying a struct
operator new: size=400 Bytes
S::S()
S::~S()
operator delete
Creating & destroying arrary of struct of size 3
operator new: size=1208 Bytes
S::S()
S::S()
S::S()
S::~S()
S::~S()
S::~S()
operator delete
Problem: If the global versions are overloaded, then this makes the default versions completely inaccessible. In such cases, the compiler cannot call the global variants even inside the redefinitions.
Example, code like the following will recursively call itself till the stack is filled.
void* operator new(size_t sz)
{
return ::new char[sz]; //Invoking global new again
}