N
Nimmi Srivastav
There's a rather nondescript book called "Using Borland C++" by Lee
and Mark Atkinson (Que Corporation) which presents an excellent
discussion of overloaded new and delete operators. In fact there are
quite a few things that I learned that I did not know before. For
example, while I knew that the new and delete operators can be
overloaded for classes, I did not know that that the global new and
delete operators can also be overloaded. Is this is Borland C++ only
function? I am asking this question since the code snippet below is
not compiling with my non-Borland C++ compiler.
Are there any other operators that can be overloaded globally?
I am presenting below a summary of what I have gathered. I would
appreciate if someone could point out to something that is specific to
Borland C++ and is not supported by the ANSI standard. I am also
concerned that some of the information may be outdated since the book
is quite old (1991 edition).
1) The use of operator new or operator delete in an expression causes
the corresponding function to be called. In other words, using
operator new causes the following function to be called:
operator new()
Using operator delete causes the following function to be called:
operator delete()
[Yeah yeah, this is kinda obvious, but I am stating it for
completeness]
2) Multi-dimensional arrays can be created with new, but with some
restrictions. All the indices must be specified, and all of them,
except the first one, must be constants. Thus the following is
legitimate syntax:
int i = 2;
intptr = new int[2][2];
3) When arrays of class objects are created with new, only the default
constructor can be used.
4) The global new operator can be overloaded as well as over-ridden.
For this you have to define a function with the following syntax:
void* operator new (/* one or two arguments*/)
{
//body ...
}
To overload, you pass two arguments to new:
size_t and void*
To over-ride, you pass only one argument to new:
size_t
5) The global delete operator can only be over-ridden. For this you
have to define a function with the following syntax:
void operator delete (/* one or two arguments*/)
{
//body ...
}
The type of the first argument is void *. The type of the second
argument, which is optional, is size_t
6) C++ recognizes the use of operator new-with-placement-syntax. This
is basically a pointer to the area (in memory) in which the entity is
to be constructed. new-with-placement-syntax creates the object at a
specific location.
7) The global new operator with placement syntax looks like this:
:: new(location pointer) type [dimension] (initializers)
The following are optional:
::
[dimension]
(initializers)
8) Whenever new is used with placement syntax, you are required to
overload the operator new
9) To instantiate an array of objects, you have to use
new-with-placement-syntax
10) Do not use delete to destroy a class object that has been
instantiated by new-with-placement-syntax. The correct approach is to
call the destructor explicitly and then separately release the storage
occupied by the object
// ~~~~~~~ Code snippet begin ~~~~~~~
#include <iostream.h>
//
// Overloading new operator
// (for use with new-with-placement-syntax)
void* operator new( size_t size, void *where)
{
cout << "Overloaded new operator" << endl;
size = size; // Dummy statement avoids compiler warning
return where; // Here is what we are after
}
//
// Overriding new operator ---- initializes the returned
// memory to null
//
void* operator new(size_t size)
{
cout << "Overridden new operator" << endl;
void* ptr;
ptr = malloc(size);
if(!ptr) return ptr; // Return null if failed
memset(ptr, '\0', size); // Do init for user
return ptr; // Return ptr by value
}
//
// Overriding delete operator
//
void operator delete( void *obj, size_t size)
{
cout << "Overridden delete operator" << endl;
// The size parameter is useless here
free(obj);
}
//
// Declare a simple class (simple_1)
//
class simple_1
{
int stuff;
public:
simple_1(int arg = 16) { stuff = arg; }
~simple_1() {}
void showit() { cout << stuff << "\r\n"; }
};
//
// Declare another simple class (simple_2)
//
class simple_2
{
int a, b, c, d, e;
public:
simple_2(): a(37), b(37), c(37), d(37), e(37)
{
cout << "HeLLo!\r\n";
}
~simple_2() { cout << "Goodbye!\r\n"; }
};
//////////////////////////////////////////////////////////////////////
int main()
{
/********** 1 **********/
// Using the overloaded new operator
// Declare a void pointer that will be used to locate
// the class object
void *fetch;
// Acquire the memory necessary to bold the object
// using original global new
fetch = (void *)
:new unsigned char[sizeof(simple_1)]);
// Declare a pointer to a class object of the desired type
simple_1* X;
// Use the overloaded new-witb-placement-syntax operator to
// construct the class object, passing the constructor
// initiatizer value as the argument
X = new(fetch) simple_1(37);
// Use the object however you want
X->showit();
// Call the destructor function explicitly. There is no
// delete for the class object in this case. So if you
// don't call the destructor explicitly, it is not called
// at all
X->~simple_1();
// Release the memory used to bold the object.
//delete fetch;
free (fetch);
/********** 2 **********/
// Over-ridden new and delete operators work well with
// basic types
char* str;
str = new char[41];
delete str;
/********** 3 **********/
// Here we will use the over-ridden new and delete operators
// with classes. These work well as long as we don't use any
// arrays of class objects
simple_2* oneobj = new simple_2;
delete oneobj; // All stiLL OK for ONE class object
/********** 3 **********/
// Here we will attempt to instantiate arrays of class objects.
// We will have to use the new-with-placement-syntax
// (overloaded new operator)
// Set up the void* pointer that will locate the array
void* oarray;
// Acquire the memory for the whole array (using the sizeof
// operator). You can use standard C library routines or
// :: new for this purpose
oarray = ::new unsigned char[10*sizeof(simple_2)];
// Declare a pointer to the class object, and initialize it witb
// new-with-placement-syntax. Use the array size declarator
// The constructors for each class object is properly called.
simple_2* bunch = new(oarray) simple_2[10];
// Be careful here, using pointer-subscript
// equivalence
// After using the array of class objects, wrte a loop in
// whicb you directly call the destructor functionfor every
// class object in the array.
for (int i=0; i < 10; ++i) bunch.~simple_2();
// Release the block of memory holding the
// array.
//delete oarray;
free(oarray);
}
// ~~~~~~~ Code snippet end ~~~~~~~
Thanks,
Nimmi
and Mark Atkinson (Que Corporation) which presents an excellent
discussion of overloaded new and delete operators. In fact there are
quite a few things that I learned that I did not know before. For
example, while I knew that the new and delete operators can be
overloaded for classes, I did not know that that the global new and
delete operators can also be overloaded. Is this is Borland C++ only
function? I am asking this question since the code snippet below is
not compiling with my non-Borland C++ compiler.
Are there any other operators that can be overloaded globally?
I am presenting below a summary of what I have gathered. I would
appreciate if someone could point out to something that is specific to
Borland C++ and is not supported by the ANSI standard. I am also
concerned that some of the information may be outdated since the book
is quite old (1991 edition).
1) The use of operator new or operator delete in an expression causes
the corresponding function to be called. In other words, using
operator new causes the following function to be called:
operator new()
Using operator delete causes the following function to be called:
operator delete()
[Yeah yeah, this is kinda obvious, but I am stating it for
completeness]
2) Multi-dimensional arrays can be created with new, but with some
restrictions. All the indices must be specified, and all of them,
except the first one, must be constants. Thus the following is
legitimate syntax:
int i = 2;
intptr = new int[2][2];
3) When arrays of class objects are created with new, only the default
constructor can be used.
4) The global new operator can be overloaded as well as over-ridden.
For this you have to define a function with the following syntax:
void* operator new (/* one or two arguments*/)
{
//body ...
}
To overload, you pass two arguments to new:
size_t and void*
To over-ride, you pass only one argument to new:
size_t
5) The global delete operator can only be over-ridden. For this you
have to define a function with the following syntax:
void operator delete (/* one or two arguments*/)
{
//body ...
}
The type of the first argument is void *. The type of the second
argument, which is optional, is size_t
6) C++ recognizes the use of operator new-with-placement-syntax. This
is basically a pointer to the area (in memory) in which the entity is
to be constructed. new-with-placement-syntax creates the object at a
specific location.
7) The global new operator with placement syntax looks like this:
:: new(location pointer) type [dimension] (initializers)
The following are optional:
::
[dimension]
(initializers)
8) Whenever new is used with placement syntax, you are required to
overload the operator new
9) To instantiate an array of objects, you have to use
new-with-placement-syntax
10) Do not use delete to destroy a class object that has been
instantiated by new-with-placement-syntax. The correct approach is to
call the destructor explicitly and then separately release the storage
occupied by the object
// ~~~~~~~ Code snippet begin ~~~~~~~
#include <iostream.h>
//
// Overloading new operator
// (for use with new-with-placement-syntax)
void* operator new( size_t size, void *where)
{
cout << "Overloaded new operator" << endl;
size = size; // Dummy statement avoids compiler warning
return where; // Here is what we are after
}
//
// Overriding new operator ---- initializes the returned
// memory to null
//
void* operator new(size_t size)
{
cout << "Overridden new operator" << endl;
void* ptr;
ptr = malloc(size);
if(!ptr) return ptr; // Return null if failed
memset(ptr, '\0', size); // Do init for user
return ptr; // Return ptr by value
}
//
// Overriding delete operator
//
void operator delete( void *obj, size_t size)
{
cout << "Overridden delete operator" << endl;
// The size parameter is useless here
free(obj);
}
//
// Declare a simple class (simple_1)
//
class simple_1
{
int stuff;
public:
simple_1(int arg = 16) { stuff = arg; }
~simple_1() {}
void showit() { cout << stuff << "\r\n"; }
};
//
// Declare another simple class (simple_2)
//
class simple_2
{
int a, b, c, d, e;
public:
simple_2(): a(37), b(37), c(37), d(37), e(37)
{
cout << "HeLLo!\r\n";
}
~simple_2() { cout << "Goodbye!\r\n"; }
};
//////////////////////////////////////////////////////////////////////
int main()
{
/********** 1 **********/
// Using the overloaded new operator
// Declare a void pointer that will be used to locate
// the class object
void *fetch;
// Acquire the memory necessary to bold the object
// using original global new
fetch = (void *)
// Declare a pointer to a class object of the desired type
simple_1* X;
// Use the overloaded new-witb-placement-syntax operator to
// construct the class object, passing the constructor
// initiatizer value as the argument
X = new(fetch) simple_1(37);
// Use the object however you want
X->showit();
// Call the destructor function explicitly. There is no
// delete for the class object in this case. So if you
// don't call the destructor explicitly, it is not called
// at all
X->~simple_1();
// Release the memory used to bold the object.
//delete fetch;
free (fetch);
/********** 2 **********/
// Over-ridden new and delete operators work well with
// basic types
char* str;
str = new char[41];
delete str;
/********** 3 **********/
// Here we will use the over-ridden new and delete operators
// with classes. These work well as long as we don't use any
// arrays of class objects
simple_2* oneobj = new simple_2;
delete oneobj; // All stiLL OK for ONE class object
/********** 3 **********/
// Here we will attempt to instantiate arrays of class objects.
// We will have to use the new-with-placement-syntax
// (overloaded new operator)
// Set up the void* pointer that will locate the array
void* oarray;
// Acquire the memory for the whole array (using the sizeof
// operator). You can use standard C library routines or
// :: new for this purpose
oarray = ::new unsigned char[10*sizeof(simple_2)];
// Declare a pointer to the class object, and initialize it witb
// new-with-placement-syntax. Use the array size declarator
// The constructors for each class object is properly called.
simple_2* bunch = new(oarray) simple_2[10];
// Be careful here, using pointer-subscript
// equivalence
// After using the array of class objects, wrte a loop in
// whicb you directly call the destructor functionfor every
// class object in the array.
for (int i=0; i < 10; ++i) bunch.~simple_2();
// Release the block of memory holding the
// array.
//delete oarray;
free(oarray);
}
// ~~~~~~~ Code snippet end ~~~~~~~
Thanks,
Nimmi