如何在C++中处理bad_alloc?
-
13-11-2019 - |
题
有一种方法叫做 foo
这有时会返回以下错误:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Abort
有没有办法,我可以使用一个 try
-catch
阻止停止此错误终止我的程序(我想要做的就是返回 -1
)?
如果是这样,它的语法是什么?
我还能怎么处理 bad_alloc
在C++中?
解决方案
您可以像任何其他例外捕获它:
try {
foo();
}
catch (const std::bad_alloc&) {
return -1;
}
.
你可以从这一点开始做的事情取决于你,但它在技术上肯定是可行的。
其他提示
一般来说,你 不能, ,而 不应该尝试, ,以响应此错误。 bad_alloc
指示无法分配资源,因为没有足够的内存可用。在大多数情况下,你的程序不能指望应付这种情况,并且很快终止是唯一有意义的行为。
更糟糕的是,现代操作系统经常过度分配:在这样的系统, malloc
和 new
一个有效的指针是否可以,即使没有足够的可用内存 – std::bad_alloc
永远不会被抛出,或者至少不是内存耗尽的可靠标志。相反,试图 查阅资料 然后,分配的内存将导致分段错误,这是不可捕获的(您可以 手柄 的分段故障信号,但之后不能恢复程序)。
捕捉时你唯一能做的事 std::bad_alloc
是为了记录错误,并尝试通过释放未完成的资源来确保安全的程序终止(但是如果程序适当地使用RAII,则在错误抛出后的正常堆栈展开过程中会自动完成)。
在某些情况下,程序可能会尝试释放一些内存并重试,或者使用辅助内存(=磁盘)而不是RAM,但这些机会仅存在于具有严格条件的非常特定的场景中:
- 应用程序必须确保它在不会过度使用内存的系统上运行, ,即它在分配时而不是以后发出失败的信号。
- 应用程序必须能够释放内存 立即, ,在此期间没有任何进一步的意外分配。
非常罕见的是,应用程序可以控制点1-用户空间应用程序 从来没有 做,这是一个系统范围的设置,需要root权限才能更改。1
好吧,假设你已经确定了第1点。你现在可以做的是例如使用 LRU缓存 对于您的一些数据(可能是一些可以按需重新生成或重新加载的特别大的业务对象)。接下来,您需要将可能失败的实际逻辑放入支持重试的函数中—换句话说,如果它被中止,您可以重新启动它:
lru_cache<widget> widget_cache;
double perform_operation(int widget_id) {
std::optional<widget> maybe_widget = widget_cache.find_by_id(widget_id);
if (not maybe_widget) {
maybe_widget = widget_cache.store(widget_id, load_widget_from_disk(widget_id));
}
return maybe_widget->frobnicate();
}
…
for (int num_attempts = 0; num_attempts < MAX_NUM_ATTEMPTS; ++num_attempts) {
try {
return perform_operation(widget_id);
} catch (std::bad_alloc const&) {
if (widget_cache.empty()) throw; // memory error elsewhere.
widget_cache.remove_oldest();
}
}
// Handle too many failed attempts here.
但即使在这里,使用 std::set_new_handler
而不是处理 std::bad_alloc
提供相同的好处,并且会简单得多。
1 如果你正在创建一个应用程序, 是否 控制点1,你正在阅读这个答案,请给我发一封电子邮件,我真的很好奇你的情况。
什么是C++标准所规定的行为 new
c++?
通常的概念是,如果 new
操作者不能分配的动态存储器的要求的大小,那么它应该把一个异常的类型 std::bad_alloc
.
然而,更多的东西会发生甚至之前 bad_alloc
异常:
C++03部分3.7.4.1.3: 说的
一个分配功能的未分配储存可以调用的目前安装new_handler(18.4.2.2),如果有的话。[注:一程序提供的分配功能可以得到的地址的当前安装new_handler使用set_new_handler功能(18.4.2.3).] 如果分配功能的声明具有一个空的例外规定(15.4),扔(),未分配储存,应当返回的一个空的指针。任何其它分配功能的未分配储存应只指明的失败抛-ing一个例外的类std::bad_alloc(18.4.2.1)或某一类源自std::bad_alloc.
考虑下列代码样本:
#include <iostream>
#include <cstdlib>
// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
std::cerr << "Unable to satisfy request for memory\n";
std::abort();
}
int main()
{
//set the new_handler
std::set_new_handler(outOfMemHandler);
//Request huge memory size, that will cause ::operator new to fail
int *pBigDataArray = new int[100000000L];
return 0;
}
在上述例子中, operator new
(最有可能)将无法分配空间,为100,000,000个整数和功能 outOfMemHandler()
将称,该程序将中止后 发出错误信息。
因为在这里看到默认的行为 new
操作时无法履行存储器的请求,是要叫 new-handler
功能反复,直至它能够找到足够的存储器或没有更多新的处理程序。在上述实例中,除非我们呼 std::abort()
, outOfMemHandler()
将会是 所谓的重复.因此,处理程序应确保,未来分配成功,或登记另一种处理程序,或者登记册没有处理程序,或者不使返回(即终止程序)。如果没有新的处理程序和分配失败,操作者将把一个例外。
什么是的 new_handler
和 set_new_handler
?
new_handler
是typedef为指针指向一个函数,以及返回什么都没有, set_new_handler
是一个函数,以及返回 new_handler
.
是这样的:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
set_new_handler的参数为指针的功能操作 new
应该呼吁,如果它不能拨出所要求的记忆。其返回值是指向以前登记的处理程序功能,或null如果没有以前的处理程序。
如何处理内存条件C++?
给定的行为 new
一个设计良好的用户程序应该处理的内存条件,通过提供正确的 new_handler
这不下列之一:
使更多的存储器可用: 这可以允许下一个存储器分配尝试的内部操作新的循环,要取得成功。一种方式来实现这个是分配一大块的存在程序启动时,然后释放,它使用的程序的第一时间的新的处理程序是援引。
安装不同的新的处理程序: 如果当前的新的处理程序不能做任何更多的存储器可用,还有另外一个新的处理程序,可以,那么当前的新的处理程序可以安装其他新的处理程序在它的地方(通过调用 set_new_handler
).下一次操作者的新电话的新的处理程序功能,它将得到一个最近安装。
(对这一主题的变化是一个新的处理程序修改它自己行为,所以接下来的时间调用的,它并不同的东西。实现这一点的一个办法是有的新的处理程序修改静态的,名字空间的特定的或全球的数据,影响新的处理程序的行为。)
卸载的新的处理程序: 这样做是通过一个空的指针 set_new_handler
.没有新的处理程序安装, operator new
将把一个异常((敞篷车) std::bad_alloc
)时存分配是不成功的。
扔一个例外 敞篷车 std::bad_alloc
.这种例外不被抓到 operator new
, 但将传播给网站发起的请求,用于存储器。
不返回: 通过调用 abort
或 exit
.
我不会建议这一点,因为 bad_alloc
意味着你是 内存不足.最好是放弃而不是试图恢复。但是,这是您要求的解决方案:
try {
foo();
} catch ( const std::bad_alloc& e ) {
return -1;
}
我可能会为此建议一个更简单(甚至更快)的解决方案。 new
如果无法分配内存,operator将返回null。
int fv() {
T* p = new (std::nothrow) T[1000000];
if (!p) return -1;
do_something(p);
delete p;
return 0;
}
我希望这可以帮助!
让你的 foo程序退出 方式:
.
#include <stdlib.h> /* exit, EXIT_FAILURE */
try {
foo();
} catch (const std::bad_alloc&) {
exit(EXIT_FAILURE);
}
然后写一个