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

Discussion in 'C++' started by Nimmi Srivastav, Jan 31, 2004.

  1. 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
    Nimmi Srivastav, Jan 31, 2004
    #1
    1. Advertising

  2. "Nimmi Srivastav" <> wrote in message
    news:...
    > 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 <new>

    >
    > 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
    John Harrison, Feb 1, 2004
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris E. Yoon
    Replies:
    2
    Views:
    388
    Michiel Salters
    Jul 23, 2003
  2. HeroOfSpielburg
    Replies:
    1
    Views:
    387
    Alf P. Steinbach
    Aug 6, 2003
  3. Piotre Ugrumov
    Replies:
    3
    Views:
    368
    Nick Hounsome
    Jan 25, 2004
  4. Replies:
    1
    Views:
    1,116
    SuperKoko
    Oct 2, 2006
  5. Alex Vinokur
    Replies:
    3
    Views:
    499
    Zoltan Juhasz
    Jun 15, 2012
Loading...

Share This Page