DEV Community

pratheek87
pratheek87

Posted on

C++ - Handling memory allocation failures when using the new operator.

The below code is to demonstrate how to handle memory allocation failures when creating objects of custom class as well as existing data types.

Key concepts:

  1. Using the set_new_handler function.
  2. Global handlers vs class specific handlers to handle memory allocation failures.

set_new_handler function

The set_new_handler method is used to set/change the custom handler function invoked when there are memory allocation failures. If not set, the new operator invokes the default handler on failure which eventually throws bad allocation error.

Syntax:

new_handler set_new_handler(new_handler p) throw();

Parameter:

A funtion poiner that receives and returns nothing.

Return value:

The value of the current new - handler function if this has already been set by this function previously, or a null
pointer if this is the first call to set_new_handler(or if it was reset by a previous call).

Note:

new_handler is a typedef for a function pointer that receives and returns nothing.

Global handlers vs class specific handlers

Code Snippet:

The below functions are used as handlers for global allocation and class object allocation

//Global
void nomemory()
{
    cerr << "No memory available" << endl;
    throw bad_alloc();
}

//Class object
void ctest_nomemory()
{
    cerr << "No memory available for allocating the class object" << endl;
    throw bad_alloc();
}

Enter fullscreen mode Exit fullscreen mode

The below test class overloads the new operator.
The currentHandler member points to the function that needs to be invoked when the allocation fails for this class.

class CTest
{
public:
    static new_handler set_new_handler(new_handler p);
    static void* operator new(size_t s);

private:
    static new_handler currHandler;

    double x[100000000];
    double x1[100000000];
    double x2[100000000];
    double x3[100000000];
    double x4[100000000];
};

//The below function overrides the std::set_new_handler method.
//The function returns the existing handler method and sets the 
//passed function as the new handler.
new_handler CTest::set_new_handler(new_handler p)
{
    new_handler old_handler = currHandler;
    currHandler = p;
    return old_handler;
}

Enter fullscreen mode Exit fullscreen mode

The below function overloads the new operator.
The std::set_new_handler function sets the global handler.
The function later sets the old handler back before the function exits.

void* CTest::operator new(size_t s)
{
    new_handler global_handler = std::set_new_handler(currHandler);

    void* memory;
    try
    {
        memory = ::operator new(s);
    }
    catch (std::bad_alloc&)
    {
        std::set_new_handler(global_handler);
        throw;
    }
    std::set_new_handler(global_handler);

    return memory;
}

//Initialize the static object 
new_handler CTest::currHandler;
Enter fullscreen mode Exit fullscreen mode

In the main method first we can see the usage of the global handler and the next snippet for the class object:

int main()
{
    //Sets the global new handler.
    set_new_handler(nomemory);

    try
    {
        for (; ; )
            double* d = new double[100000000];
    }
    catch (bad_alloc)
    {
        cout << "allocation failed" << endl;
    }

    //Sets the class CTest new handler.
    CTest::set_new_handler(ctest_nomemory);
    try {
        CTest* testObj = new CTest;
    }
    catch (std::bad_alloc&)
    {
        cout << "allocation failed" << endl;
    }

    return 1;
}
Enter fullscreen mode Exit fullscreen mode

Output:

No memory available
allocation failed

No memory available for allocating the class object
allocation failed

Top comments (0)