如何处理C ++中的bad_alloc?
有一个名为foo
的方法,有时会返回以下错误:
terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Abort
有没有办法,我可以使用try
– catch
块来阻止这个错误终止我的程序(我想要做的就是返回-1
)?
如果是这样,它的语法是什么?
我还能怎样处理C ++中的bad_alloc
?
你可以像其他任何exception一样捕获它:
try { foo(); } catch (const std::bad_alloc&) { return -1; }
从这一点来看,你可以做的有用的工作是由你自己决定的,但从技术上来说绝对是可行的。
一般来说,你不能也不 应该试图回应这个错误。 bad_alloc
表示由于内存不足而无法分配资源。 在大多数情况下,你的程序不能希望应付这种情况,很快终止是唯一有意义的行为。
更糟糕的是,现代操作系统经常过度分配: malloc
和new
将始终返回一个有效的指针,即使技术上没有(或不足)剩余内存 – 所以std::bad_alloc
将永远不会被抛出,或者至less不会内存耗尽的可靠迹象。 相反,试图访问分配的内存将导致错误,这是不可捕捉的。
捕获std::bad_alloc
时唯一可以做的事情就是logging错误,并通过释放未完成的资源来确保程序的安全终止(但是这是在错误被抛出后,在正常的堆栈展开过程中自动完成的该程序适当地使用RAII)。
在某些情况下,程序可能会尝试释放一些内存并再次尝试,或使用辅助内存(=磁盘)而不是RAM,但是这些机会只存在于特定的情况下。
什么是C ++标准指定new
的C + +的行为?
通常的概念是,如果new
运算符不能分配所需大小的dynamic内存,则应该抛出std::bad_alloc
types的exception。
但是,即使在引发bad_alloc
exception之前,也会发生更多的事情:
C ++ 03第3.7.4.1.3节:说
分配存储失败的分配函数可以调用当前安装的new_handler(18.4.2.2),如果有的话。 [注:程序提供的分配函数可以使用set_new_handler函数(18.4.2.3)获取当前安装的new_handler的地址。]如果一个用空exception规范(15.4)throw()声明的分配函数不能分配存储,它应该返回一个空指针。 任何其他分配函数都不能分配存储空间,只能通过抛出std :: bad_alloc(18.4.2.1)类或从std :: bad_alloc派生的类的exception来指示失败。
考虑下面的代码示例:
#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
函数,直到find足够的内存或者没有更多的新处理程序。 在上面的例子中,除非我们调用std::abort()
, outOfMemHandler()
会重复调用 outOfMemHandler()
。 因此,处理程序应该确保下一个分配成功,或者注册另一个处理程序,或者不注册处理程序,或者不返回(即终止程序)。 如果没有新的处理程序,分配失败,则操作员将抛出exception。
什么是new_handler
和set_new_handler
?
new_handler
是指向一个函数的指针的typedef,它返回一个new_handler
并且返回一个new_handler
的函数, set_new_handler
是一个函数。
就像是:
typedef void (*new_handler)(); new_handler set_new_handler(new_handler p) throw();
set_new_handler的参数是一个指向函数操作符的指针,如果new
操作符不能分配请求的内存,它应该调用它。 它的返回值是一个指向先前注册的处理函数的指针,如果没有以前的处理函数,则返回null。
如何处理在C + +的内存条件?
鉴于new
的devise良好的用户程序的行为应该通过提供一个适当的new_handler
来处理内存不足的情况:
使更多的内存可用:这可能允许运算符new循环内的下一次内存分配尝试成功。 实现这一点的一种方法是在程序启动时分配一大块内存,然后在第一次调用新处理程序时释放它以供程序使用。
安装一个不同的新处理程序:如果当前的新处理程序不能再提供更多的内存,并且有另一个新的处理程序可以,那么当前的新处理程序可以将其他新的处理程序安装在它的位置通过调用set_new_handler
)。 下次运算符new调用new-handler函数时,它将得到最近安装的那个函数。
(这个主题的一个变种是为了让新处理程序修改自己的行为,所以在下一次被调用的时候,它会做一些不同的事情。一种方法是让新处理程序修改静态的,特定于命名空间的全局数据影响新处理程序的行为。)
卸载新的处理程序:这是通过将空指针传递给set_new_handler
来set_new_handler
。 在没有安装新处理程序的情况下, operator new
将在内存分配不成功时抛出exception((可转换为) std::bad_alloc
)。
抛出一个可转换为std::bad_alloc
的exception 。 这样的exception不会被operator new
捕获,而是会传播到发起内存请求的站点。
不返回:通过调用abort
或exit
。
我不会提出这个build议,因为bad_alloc
意味着你已经失去了记忆 。 最好放弃而不是试图恢复。 但是,这是您要求的解决scheme:
try { foo(); } catch ( const std::bad_alloc& e ) { return -1; }
我可能会build议一个更简单(甚至更快)的解决scheme。 如果内存不能分配, new
运算符将返回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); }
然后编写一个调用实际程序的shell程序。 由于地址空间是分开的,所以你的shell程序的状态总是很好定义的。