_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++ 语言参考”中的 new
和 delete
。
单个进程中所有动态链接的 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
*/