_set_new_handler

如果 new 运算符无法分配内存,则将控制权传输到错误处理机制。 Microsoft C++ 编译器使用此函数在标准库中实现 std::set_new_handler

语法

_PNH _set_new_handler( _PNH pNewHandler );

参数

pNewHandler
指向应用程序提供的内存处理函数的指针。 自变量为 0 或 nullptr 会导致新的处理程序被移除。

返回值

返回指向由 _set_new_handler 注册的上一个异常处理函数的指针,以便稍后能还原上一个函数。 如果之前没有设置函数,则可使用返回值还原默认行为。 此值可为 nullptr 或 0。

备注

如果 _set_new_handler 运算符无法分配内存,则 C++ new 函数将指定获取控制权的异常处理函数。 如果 new 失败,则运行时系统将自动调用已作为参数传递给 _set_new_handler 的异常处理函数。 <new.h> 中定义的 _PNH 是一个指向函数的指针,该函数返回 int 类型并采用 size_t 类型的自变量。 使用 size_t 指定要分配的空间量。

没有默认处理程序。

_set_new_handler 实际上是垃圾回收方案。 如果您的函数返回非零值,则运行时系统会重试分配;如果您的函数返回 0,则将失败。

程序中的 _set_new_handler 函数的匹配项将向运行时系统注册参数列表中指定的异常处理函数:

// _set_new_handler1.cpp
#include <new.h>

int handle_program_memory_depletion( size_t )
{
   // Your code
}

int main( void )
{
   _set_new_handler( handle_program_memory_depletion );
   int *pi = new int[BIG_NUMBER];
}

默认情况下,_set_new_handler 函数的全局状态范围限定为应用程序。 若要更改此状态,请参阅 CRT 中的全局状态

您可以保存最后传递给 _set_new_handler 函数的函数地址,并在稍后恢复它:

   _PNH old_handler = _set_new_handler( my_handler );
   // Code that requires my_handler
   // . . .
   _set_new_handler( old_handler )
   // Code that requires old_handler
   // . . .

C++ _set_new_mode 函数将为 malloc 设置新的处理程序模式。 新的处理程序模式将指示 malloc 是否在失败时调用由 _set_new_handler 设置的新处理程序例程。 默认情况下,malloc 在失败时不调用新的处理程序例程来分配内存。 可以替代此默认行为,以便在 malloc 无法分配内存时,malloc 将以 new 运算符由于相同原因失败时的同一方法调用新的处理程序例程。 若要替代默认值,请提前在程序中调用 _set_new_mode(1); 或链接到 newmode.obj

如果提供了用户定义的 operator new,则在失败时不自动调用新的处理程序函数。

有关详细信息,请参阅“C++ 语言参考”中的 newdelete

单个进程中所有动态链接的 DLL 或可执行文件都有一个 _set_new_handler 处理程序。 即使调用 _set_new_handler,处理程序也可能被另一个处理程序取代。 或者,新处理程序可能会取代进程中由另一个 DLL 或可执行文件设置的处理程序。

要求

函数 必需的标头
_set_new_handler <new.h>

有关兼容性的详细信息,请参阅 兼容性

示例

在此示例中,当分配失败时,控制将转移给 MyNewHandler。 传递给 MyNewHandler 的自变量是请求的字节数。 从 MyNewHandler 返回的值是一个指示是否应重试分配的标志:非零值指示应重试分配,零值指示分配已失败。

// crt_set_new_handler.cpp
// Build for x86. 
// WARNING: This code intentionally allocates memory until an allocation fails.
// Running this code can cause your system to become non-responsive.
#include <iostream>
#include <new>
#include <new.h>

static const int Big_number = 0x03FFFFFF;

struct MemoryHog {
    int pork[Big_number];
};

class MemoryReserve {
    MemoryHog* reserved = nullptr;
public:
    MemoryReserve() {
        reserved = new MemoryHog();
    }
    ~MemoryReserve() noexcept {
        if (reserved != nullptr)
            delete reserved;
    }
    bool free_reserve() noexcept {
        if (reserved != nullptr) {
            delete reserved;
            reserved = nullptr;
            return true; // return true if memory freed
        }
        return false; // reserved memory exhausted.
    }
};

// Global singleton for a MemoryReserve object
static MemoryReserve reserve{};

// Define a function to be called if new fails to allocate memory.
int MyNewHandler(size_t /* unused */)
{
    // Call a function to recover some heap space. Return 1 on success.
    if (reserve.free_reserve()) {
        std::cerr << "MyNewHandler: Released reserved memory.\n";
        return 1;
    }
    std::cerr << "MyNewHandler: Reserved memory exhausted.\n";
    return 0;
}

static const int max_depth = 16; // recursion depth limiter
static int depth = 0;

void RecurseAlloc() {
    MemoryHog* piggy = new MemoryHog{};
    if (++depth < max_depth) // Recurse until memory exhausted or max_depth
        RecurseAlloc();
    depth--;
    delete piggy;
    return;
}

int main()
{
    try {
        _set_new_handler(MyNewHandler); // Set handler for new.
        RecurseAlloc();
    }
    catch (std::bad_alloc& ex) {
        std::cerr << "bad_alloc caught: " << ex.what() << '\n';
    }
}

/* Output:
MyNewHandler: Released reserved memory.
MyNewHandler: Reserved memory exhausted.
bad_alloc caught: bad allocation
*/

另请参阅

内存分配
calloc
free
realloc