Overloading New and Delete Operators at Global and Class level

We can make operators function for user-defined classes in C++. This means that C++ has the power to give operators a special meaning for a data form, which is referred to as operator overloading.
For example, in a class like String, we can overload the operator ‘+’ so that we can concatenate two strings with only +.
Complex Number, Fractional Number, Big Integer, and other groups are examples of overloaded arithmetic operators.

Overloading New and Delete Operators

1)New Operator

A request for memory allocation on the Free Store is denoted by the new operator. The new operator allocates memory and returns the address of the newly allocated and initialised memory to the pointer variable if enough memory is available.

2)Delete Operator

Since it is the duty of the programmer to deallocate dynamically allocated memory, the C++ language provides a delete operator.

3)Internal Working of New and Delete Operators

When we call the new operator to build a new Object on the heap, it does the following things internally:

  • It first allocates the necessary memory by calling operator new, which returns the top memory pointer.
  • It then calls the constructor of the specified Kind to initialise the memory.

Similarly, when we erase dynamically allocated memory, it performs the following internal operations:

  • It first de-initializes the memory by calling the specified Type’s Destructor.
  • It then calls operator delete to erase the allocated memory.

Assume a new requirement arises, such as a new/delete operator to perform certain special operations when allocating memory, i.e.

  • Rather than allocating raw memory from the heap each time, use memory from a memory pool, i.e. fetch memory from a memory pool and return it after usage.
  • Do some logging, bookkeeping, and decision making while allocating and deallocating memory, such as keeping track of how much memory has been used, and so on.

4)Overloading at global level

Below is the implementation:

#include <cstdlib>
#include <iostream>
using namespace std;
// Global new operator overloading
void* operator new(size_t size)
{
    void* mem = malloc(size);
    cout << "User Defined new operator " << endl;

    return mem;
}
// Global delete operator overloading
void operator delete(void* mem)
{
    cout << "User Defined delete operator" << endl;
    free(mem);
}
// Global new[] operator Overloading
void* operator new[](size_t size)
{
    cout << "User Defined Operator new []" << endl;
    void* mem = malloc(size);
    return mem;
}
// Global delete[] operator Overloading
void operator delete[](void* mem)
{
    cout << "User Defined Operator delete[]" << endl;
    free(mem);
}
class Sample {
public:
    Sample() { cout << "Sample Constructor" << endl; }
    ~Sample() { cout << "Sample Destructor" << endl; }
};
int main()
{ // using new creating new variable
    int* pointer = new int;
    // deleting using delete
    delete pointer;
    Sample* samplePtr = new Sample;
    delete samplePtr;
    int* arraypointer = new int[100];
    delete[] arraypointer;
    return 0;
}

Output:

User Defined new operator 
User Defined delete operator
User Defined new operator 
Sample Constructor
Sample Destructor
User Defined delete operator
User Defined Operator new []
User Defined Operator delete[]

To keep dynamic array allocation in line with other objects, we need to overload new[] and delete[] along with new & delete.

As we can see, the new and delete operators have been overloaded at the global level, so any object generated on the heap by the new operator was created by our custom overloaded operator.

5)Overloading at specific class

Below is the implementation:

#include <cstdlib>
#include <iostream>
using namespace std;
class Sample {
public:
    Sample() { cout << "Sample Constructor" << endl; }
    ~Sample() { cout << "Sample Destructor" << endl; }
    // class specific new operator overloading
    static void* operator new(size_t size)
    {
        void* mem = malloc(size);
        cout << "Sample class Operator new" << endl;
        return mem;
    }
    // class specific delete operator overloading
    static void operator delete(void* mem)
    {
        cout << "Sample class Operator delete" << endl;
        free(mem);
    }
};
int main()
{
    int* pointer = new int;
    delete pointer;
    Sample* sampleptr = new Sample;
    delete sampleptr;
    return 0;
}

Output:

Sample class Operator new
Sample Constructor
Sample Destructor
Sample class Operator delete

In this way we can overload in specific class.
Related Programs: