[C + + memory management] 7_ new handler

Time:2022-5-9

When operator new is unable to allocate the memory we applied for, an STD:: bad will be thrown_ alloc exception。 Some older compilers return 0, which modern compilers can still do:new (nothrow) Foo;

Before throwing exception, a handler that can be specified by the client will be called (more than once). The following is the form and setting method of new handler:

typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
  • Well designed new_ Handler has only two choices:

    • Make more memory available
    • callabort()orexit()
void *operator_new(size_t size, const std::nothrow_t &_THROW0())
{
    // try to allocate size bytes
    void *p;
    while ((p = malloc(size)) == 0)
    {
        // buy more memory or return null pointer
        _TRY_BEGIN
            if (_callnew_h(size) == 0) break;
        _CATCH(std::bad_alloc) return 0;
        _CATCH_END
    }
    return (p);
}
#include <new>
#include <iostream>
#include <cassert>

using namespace std;

void onMoreMemory()
{
    cerr << "out of memory" << endl;
    abort();
}

int main()
{
    set_new_handler(onMoreMemory);

    int *p = new int[10000];
    assert(p);
    cout << p << endl;

    p = new int[100000000000000];
    assert(p);
    cout << p << endl;

    return 0;
}

Output [GCC version 7.5.0]

0x55ad89dd7e70
out of memory
Aborted (core dumped)

In this example, if abort() is not called in the new handler, the “out of memory” will continue to appear in the cerr after execution, which needs to be forcibly interrupted. This performance is correct, which means that when the operator new cannot meet the application volume, it will continue to call the new handler until it gets enough memory

default、delete

Default and delete are not only applicable to constructors (copy construction and move construction) and assignment functions (copy assignment and move assignment)

class Foo {
public:
    Foo() = default;
    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;
    ~Foo() = default;
};

Actual test:

#include <iostream>

using namespace std;

class Foo {
public:
    long _x;
public:
    Foo(long x = 0) : _x(x)
    { }

    // static void *operator new(size_t size) = default;                   // error: only special member functions may be defaulted
    // static void operator delete(void *pdead, size_t size) = default;    // error: only special member functions may be defaulted
    static void *operator new[](size_t size) = delete;
    static void operator delete[](void *pdead, size_t size) = delete;
};

int main()
{
    // Foo *p1 = new Foo[10];  // error: call to deleted function 'operator new[]'
    // delete []  p1;          // error: attempt to use a deleted function

    return 0;
}