从C++ 11标准(15.1.p4):
除非在3.7.4.1中指出,否则异常对象的内存以未指定的方式分配
如果分配失败怎么办 - 它会抛出std::bad_alloc吗?打电话std::terminate?未指定?
C.M*_*.M. 11
(提供我自己的答案......我会等几天,如果没有问题 - 我会将其标记为已接受)
我花了一些时间来研究这个,这就是我发掘出来的:
Itanimum ABI建议将堆用于异常:
抛出异常需要存储.这个存储必须在堆栈被解除时保持不变,因为它将由处理程序使用,并且必须是线程安全的.因此,异常对象存储通常将在堆中分配
...
内存将由
__cxa_allocate_exception运行时库例程分配.
所以,是的...抛出异常可能涉及锁定互斥锁并搜索空闲内存块.:-(
它还提到了这个:
如果__cxa_allocate_exception无法在这些约束下分配异常对象,则调用terminate()
是的...在GCC和Clang"扔myX();" 可以杀死你的应用程序,你不能做任何事情(也许写你自己__cxa_allocate_exception可以帮助 - 但它肯定不会是便携式的)
它变得更好:
3.4.1分配异常对象
异常对象的内存将由__cxa_allocate_exception运行时库例程分配,其一般要求如第2.4.2节中所述.如果正常分配失败,那么它将尝试在以下约束条件下分配第3.3.1节中描述的紧急缓冲区之一:
- 异常对象大小(包括标题)小于1KB.
- 当前线程尚未包含四个缓冲区.
- 有少于16个其他线程持有缓冲区,或者此线程将等到其中一个线程在获取缓冲区之前释放其缓冲区.
是的,你的程序可以简单地挂起!这种情况很小 - 你需要耗尽内存并且线程需要耗尽所有16个紧急缓冲区并进入等待另一个应该生成异常的线程.但是如果你做的事情std::current_exception(比如链接异常并在线程之间传递它们) - 它不是那么不可能.
结论:
这是C++标准的缺陷 - 您无法编写100%可靠的程序(使用异常).教科书示例是一个服务器,它接受来自客户端的连接并执行提交的任务.处理问题的明显方法是抛出异常,这将解除所有内容并关闭连接 - 所有其他客户端不会受到影响,服务器将继续运行(即使在低内存条件下).唉,这样的服务器不可能用C++编写.
你可以声称现代系统(即Linux)会在我们达到这种情况之前杀死这样的服务器.但是(1)它不是一个论点; (2)内存管理器可以设置为overcommit; (3)在具有足够内存的64位硬件上运行的32位应用程序不会触发OOM杀手(或者如果app人为限制内存分配).
就个人而言,我对这一发现感到非常生气 - 多年来我声称我的代码优雅地处理了内存不足.结果我骗了我的客户.:-(还不如开始截取内存分配,调用std::terminate和处理所有相关的功能noexcept-这肯定会让我的生活更轻松(编码明智)难怪他们仍然使用的Ada程序火箭.