Global overload of new and delete ---- Borland feature only?

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
 
J

John Harrison

Nimmi Srivastav said:
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.

See below.
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]
Correct.


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];


Specifically compile time constants. The following is not OK

const int x = something(); // a constant, but not a compile time constant
int* p = new int[x];
3) When arrays of class objects are created with new, only the default
constructor can be used.
Correct.


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

The two argument one is a placement new, and is already defined.

You aren't restricted to just this, any number of arguments and types are
allowed, as long as the first is 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

Global placement deletes are allowed. Again any number any typ of arguments
are OK, as long as first is void*.
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.

That is the most common use of placement new. But really placement new is
just a way of providing extra arguments to operator new which can be used
for any purpose.
7) The global new operator with placement syntax looks like this:
:: new(location pointer) type [dimension] (initializers)

Again, any arguments are possible, e.g.

void* operator new(size_t bytes, X* px, Y* py, Z* pz);

X x;
Y y;
Z z;
new (&x, &y, &z) int;
The following are optional:
::
[dimension]
(initializers)

8) Whenever new is used with placement syntax, you are required to
overload the operator new

The commonest placement new (the one with one extra void* argument) is
already provided in header file said:
9) To instantiate an array of objects, you have to use
new-with-placement-syntax

I guess you mean instantiate an array of objects with non default ctor.
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
Correct.


// ~~~~~~~ Code snippet begin ~~~~~~~
#include <iostream.h>

Non-standard header (this is true, despite whatever books you might have
read). Replace it with

#include <iostream> // note no .h
using namespace std;

and you are standard compliant.
//
// 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
}

Above function is already defined in header <new> (again no .h). You
shouldn't define it again.

Rest of code compiles OK for me.

John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top