条款49:了解 new-handler 的行为
STL 容器使用的堆内存由容器的分配器对象管理,而不是直接通过 new
和 delete
管理。new-handler
是一个在内存分配失败时被调用的函数,可以帮助处理内存不足的情况。
使用场景
-
内存分配失败的处理:
当new
无法成功分配内存时,new-handler
被调用。可以使用set_new_handler
安装一个新的new-handler
,以便在内存分配失败时采取特定的处理措施。 -
避免直接抛出异常:
在内存分配失败的情况下,new-handler
可以选择让更多内存可用、安装新的new-handler
、卸载当前的new-handler
,或者抛出bad_alloc
异常。 -
Nothrow new:
nothrow
版本的new
运算符可以避免抛出异常,但它依然可能由于后续的构造函数调用而抛出异常,因此它的应用相对局限。
示例:设置 custom new-handler
#include <iostream> #include <new> // for std::set_new_handler void custom_new_handler() { std::cerr << "Memory allocation failed. Custom handler activated.\n"; std::terminate(); // Can choose to terminate or handle accordingly } int main() { std::set_new_handler(custom_new_handler); try { int* p = new int[10000000000]; // Likely to fail } catch (const std::bad_alloc& e) { std::cerr << "Caught exception: " << e.what() << std::endl; } return 0; }
在这个示例中,set_new_handler
安装了一个自定义的内存分配失败处理函数 custom_new_handler
,当内存分配失败时,它会输出错误信息并终止程序。
注意事项
-
设计良好的
new-handler
函数:
设计一个好的new-handler
函数时,它必须处理内存释放、安装新的new-handler
或卸载当前的new-handler
,并抛出bad_alloc
异常来通知内存分配失败。 -
Nothrow
new
的局限性:
尽管nothrow
版本的new
不会抛出异常,但它并不是万无一失的,因为后继的构造函数调用仍然可能抛出异常,因此使用时要小心。 -
异常处理:
内存分配失败时,new-handler
可以选择抛出异常,或者直接终止程序。具体选择取决于应用程序的需求和设计。
总结
new-handler
提供了一种灵活的方式来处理内存分配失败的情况。通过设置合适的 new-handler
函数,程序可以在内存不足时采取不同的措施,如释放更多内存、安装新的处理程序,或终止程序。对于现代 C++ 开发者,理解 new-handler
的使用和局限性至关重要,以便设计高效且稳定的内存管理机制。