C++. Overloading operators new and delete




Overloading operators new and delete

Before studying this topic, it is recommended to familiarize yourself with the following topic:


Contents


Search other websites:

1. When do you need to overload the operators new and delete?

The new operator must be reloaded in cases where memory is allocated in non-standard way. Accordingly, the delete operator should free this memory in a non-standard way. As a rule, if the operator new is overloaded in a class, then the operator delete is also overloaded in this class.

 

2. What methods of overload can be performed on the new and delete operators?

The new and delete operators can be overloaded in various ways. These methods differ in the declaration of an operator function. The following are all valid methods for overloading:

  • overloading the new and delete operators with an operator function that is implemented within the class. This is a way to overload new and delete for a particular class. When calling new and delete for this class, overloaded operator functions will be called that allocate/free memory in a specific way. When calling the new and delete operators for other classes, the global operators new and delete are used;
  • global overload of the operators new and delete. In this case, the new and delete operators are overloaded for built-in types (float, int, etc.).

 

3. The general form of operator overloading new

The general form of overloading the new operator is as follows:

return_type * operator new(size_t size)
{
    // Memory allocation
    // ...
}

here

  • return_type is a type (class) to which the operator function returns a pointer for which memory is allocated by a special (non-standard method);
  • size – size of memory that is allocated for return_type type. The number of bytes allocated memory does not have to match the size, since the body of the operator function memory you can allocate special.

 

4. The general form of operator overload delete

The general form of operator overload delete is as follows:

void operator delete(void * pointer)
{
    // freeing the memory pointed to by the pointer pointer
    // ...
}

here pointer – a pointer to the memory area that was previously allocated by the operator new.

 

5. For which types (classes) can the overloaded operators new and delete be used?

If the program overloads the operators new and delete, then there are two types of these operators:

  • overloaded operators new and delete. These overloaded operators are applied to a particular class, which has operator new() and operator delete();
  • global operators new and delete (not overloaded). These operators are used for classes that do not contain operator functions that overload the new and delete operators.

For each class, the compiler determines which variant of the new and delete operators to choose: global or for a specific class.






 

6. Example of overloading the new and delete operators inside a class for single objects

The example declares the class Complex, which implements a complex number. The class contains:

  • internal variables real, imag, which correspond to the real and imaginary parts of the complex number;
  • class constructor;
  • access methods Get(), Set();
  • overloaded operator functions operator new(), operator delete() which overload respectively the operators new and delete. These functions are used strictly for the Complex class. The implementation of the Complex class and the main() function, which demonstrates the overloading of the new and delete operators, is as follows:
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;

// class containing overloaded operators new and delete
class Complex
{
private:
    double real;
    double imag;

public:
    // constructor
    Complex(double _real, double _imag)
    {
        real = _real;
        imag = _imag;
    }

    // access methods
    void Get(double * r, double * i)
    {
        *r = real;
        *i = imag;
        return;
    }

    void Set(double r, double i)
    {
        real = r;
        imag = i;
    }

    // overloaded operator new,
    // allocates memory of a given size
    void * operator new(size_t size)
    {
        void * ptr;

        cout<<"Attempt to allocate memory \n";
        ptr = malloc(size); // Attempt to allocate memory

        if (!ptr) // if no memory is allocated, then generate an exception
        {
            bad_alloc ba;
            cout<<"Memory allocation error.\n";
            throw ba;
        }
        else
        {
            //
            cout<<"Memory is allocated successfully!\n";
            return ptr;
        }
    }

    // It frees the memory allocated to the overloaded
    // operator function operator new()
    void operator delete(void * ptr)
    {
        cout<<"Free the memory allocated by the delete operator.\n";
        free(ptr);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    // demonstration of the use of the new and delete operators in the Complex class
    Complex * p1; // declare a pointer to the Complex

    try
    {
        // invoke the operator function operator new()
        p1 = new Complex(5,6); // allocate memory
    }
    catch (bad_alloc error)
    {
        return 1; // exit the program with a return code 1
    }

    // free up memory
    // invoke the operator function operator delete()
    delete p1;
    return 0;
}

As a result of executing the above code, the following result will be displayed:

Attempt to allocate memory
Memory is allocated successfully!
Free the memory allocated by the delete operator.

 

7. Example of global overloading of new and delete operators for single objects

The new and delete operators can be globally overloaded. In this case, the use of the global overloaded operators new and delete can be used for any type. The following is an example of a global overload of the new and delete operators.

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
using namespace std;

// class that contains the overloaded operators new and delete
class Complex
{
private:
    double real;
    double imag;

public:
    // constructor
    Complex(double _real, double _imag)
    {
        real = _real;
        imag = _imag;
    }

    // access methods
    void Get(double * r, double * i)
    {
        *r = real;
        *i = imag;
        return;
    }

    void Set(double r, double i)
    {
        real = r;
        imag = i;
    }
};

// global operator new
void * operator new(size_t size)
{
    void * ptr;
    cout<<"Global operator new"<<::endl;
    cout<<"1. Attempting to allocate memory with the malloc function()\n";
    ptr = malloc(size); // attempt to allocate memory

    if (!ptr) // if memory is not allocated, then an exception is thrown
    {
        bad_alloc ba;
        cout<<"2. Memory allocation error.\n";
        throw ba;
    }
    else
    {
        cout<<"3. Memory allocated successfully by global operator new\n";
        return ptr;
    }
}

// global operator delete
void operator delete(void * ptr)
{
    cout<<"4. Global operator delete.\n";
    free(ptr);
}

int _tmain(int argc, _TCHAR* argv[])
{
    // demonstration of the use of the global operators new and delete
    Complex * p; // declare a pointer to the Complex
    int * p; // pointer to int

    try
    {
        // invoke the operator function operator new()
        p = new Complex(5,6); // allocate memory
    }
    catch (bad_alloc error)
    {
        cout<<"Error allocating memory for object p"<<::endl;
        return 1; // exit the program with code 1
    }

    // free up memory
    // invoke the global operator delete()
    delete pC;

    try
    {
        // call the overloaded version of the operator new
        cout<<"Attempt to allocate memory for object pI"<<::endl;
        pI = new int;
    }
    catch (bad_alloc error)
    {
        cout<<"Error allocating memory for pI "<<::endl;
        return 2; // exit the program with a return code 2
    }
    delete pI;
    return 0;
}

As a result of executing the above code, the following result will be displayed:

Global operator new
1. Attempting to allocate memory with the malloc function()
3. Memory allocated successfully by global operator new
4. Global operator delete.
Attempt to allocate memory for object pI
1. Attempting to allocate memory with the malloc function()
3. Memory allocated successfully by global operator new
4. Global operator delete.

As can be seen from the result, the global operators new and delete work both for base types and for classes.

 

8. An example of overloading the new and delete operators within the class boundaries in the case of memory allocation for an array

An example of overloading the operators new and delete for an array of objects of type Point is given. The Point class defines a point on the coordinate plane and contains the following declarations:

  • variables x, y which are the coordinates of a point;
  • constructors;
  • access methods Get(), Set();
  • the operator functions operator new() and operator delete(), implementing the allocation/release of memory for single objects of type Point;
  • operator functions operator new[]() and operator delete[](), which implement memory allocation/release for arrays of objects of type Point.

The program code that implements the Point class is as follows:

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;

class Point
{
private:
    double x, y;

public:
    // constructors
    Point()
    {
        x = y = 0.0;
    }

    Point(double _x, double _y)
    {
        x = _x;
        y = _y;
    }

    // access methods
    void Get(double * _x, double * _y)
    {
        *_x = x;
        *_y = y;
    }

    void Set(double _x, double _y)
    {
        x = _x;
        y = _y;
    }

    // overloaded operator new for single object of class Point
    void * operator new(size_t size)
    {
        void * ptr;
        ptr = malloc(size);
        if (!ptr)
        {
            bad_alloc error;
            throw error;
        }
        return ptr;
    }

    // overloaded delete statement for a single object of class Point
    void operator delete(void * ptr)
    {
        cout<<"Memory freeing using delete operator"<<::endl;
        free(ptr);
    }

    // перегруженный оператор new для массива объектов типа Point
    void * operator new[](size_t size)
    {
        void * ptr;
        cout<<"The use of an overloaded operator new[]."<<::endl;
        ptr = malloc(size);
        if (!ptr)
        {
            bad_alloc error;
            throw error;
        }
        return ptr;
    }

    // overloaded delete operator for an array of objects of type Point
    void operator delete[](void * ptr)
    {
        cout <<"Delete array from memory by operator delete[]"<<::endl;
        free(ptr);
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    // overloading the new and delete operators for arrays of objects
    Point * p1;

    try
    {
        // invoke the overloaded operator function operator new[]()
        // of class Point
        p1 = new Point[5]();
    }
    catch (bad_alloc error)
    {
        cout<<"Error allocating memory for object p1."<<::endl;
        return 1;
    }
    delete[] p1;
    return 0;
}

As a result of executing the above code, the following result will be displayed.

The use of an overloaded operator new[].
Delete array from memory by operator delete[]

Important: in order to overload the operators new and delete for arrays, it is not necessary to overload these operators for single objects.

 

9. Example of global overloading of the new[] and delete[] operators for arrays

Below is an example of global overloading of the operators new[] and delete[] for arrays of class Point

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
using namespace std;

class Point
{
private:
    double x, y;

public:
    // constructors
    Point()
    {
        x = y = 0.0;
    }

    Point(double _x, double _y)
    {
        x = _x;
        y = _y;
    }

    // access methods
    void Get(double * _x, double * _y)
    {
        *_x = x;
        *_y = y;
    }

    void Set(double _x, double _y)
    {
        x = _x;
        y = _y;
    }
};

// overloaded operator new for single object of class Point
void * operator new(size_t size)
{
    void * ptr;
    ptr = malloc(size);
    if (!ptr)
    {
        bad_alloc error;
        throw error;
    }
    return ptr;
}

// overloaded operator delete for a single object of class Point
void operator delete(void * ptr)
{
    cout<<"Releace memory using delete operator"<<::endl;
    free(ptr);
}

// overloaded operator new for an array of objects of type Point
void * operator new[](size_t size)
{
    void * ptr;
    cout<<"Using the overloaded operator new[]."<<::endl;
    ptr = malloc(size);
    if (!ptr)
    {
        bad_alloc error;
        throw error;
    }
    return ptr;
}

// overloaded delete operator for an array of objects of type Point
void operator delete[](void * ptr)
{
    cout <<"Releace array from memory by operator delete[]"<<::endl;
    free(ptr);
}

int _tmain(int argc, _TCHAR* argv[])
{
    // global overloading of the new and delete operators for arrays of objects
    Point * p1; // pointer to class Point
    float * p2; // pointer to float

    try
    {
        // invoke the overloaded global operator function operator new[]()
        // of class Point
        p1 = new Point[5]();
    }
    catch (bad_alloc error)
    {
        cout<<"Error allocating memory for object p1."<<::endl;
        return 1;
    }
    delete[] p1;

    // invoke the global operator function operator new[]() for the base type float
    try
    {
        p2 = new float[10]; // function call
    }
    catch (bad_alloc error)
    {
        cout<<"Error allocating memory for object p2."<<::endl;
        return 2;
    }
    delete[] p2;
    return 0;
}

As a result of executing the above code, the following result will be displayed:

Using the overloaded operator new[].
Releace array from memory by operator delete[]

As can be seen from the result, the overloaded global operator functions operator new[] and operator delete[] for arrays work in the same way as with the base types (float) and with the class types (Point).

 


Related topics