为什么异常总是在具有可破坏堆栈 objects 的 non-leaf 函数中产生开销?

Why do exceptions always incur overhead in non-leaf functions with destructible stack objects?

我在这里看到标题中的声明:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html

通过这里:

http://www.boost.org/doc/libs/1_57_0/doc/html/container/exception_handling.html

  • Exception handling violates the don't-pay-for-what-you-don't-use design of C++, as it incurs overhead in any non-leaf function that has destructable stack objects regardless of whether they use exception handling.

这是指什么?

我认为这个要点意味着任何在异常事件中正确展开堆栈的策略都需要 non-leaf 函数来存储一些关于可破坏的信息 objects 它们放在堆。如果这是正确的,那么我的具体问题是:

必须存储的信息是什么?

为什么仅给出发生抛出的指令地址和在 run-time 之前计算的地址范围表,为什么无法正确展开堆栈?

您以二进制大小支付。

不管你是否使用异常,所有处理异常的代码都需要存在,因为通常编译器无法知道一个函数是否可以抛出异常,除非它被标记为 noexceptnoexcept 的存在主要是出于这个原因)。

如果包含异常处理的代码进入 CPU 缓存,从而浪费缓存内存,增加的二进制文件大小也可能会损害实际的运行时性能。一个好的编译器应该能够通过将所有执行异常处理的代码存储在尽可能远离"hot"运行时路径的地方来避免这个问题。

此外,一些 ABI (SJLJ) 即使在非异常路径中也实现了具有一些运行时开销的异常。 Itanium 和 windows ABI 在非异常路径上的开销均为零(因此在这些 ABI 上,您可以期望异常比 return-error-code 错误处理更快)。

如果您对各种 ABI 中异常处理之间的差异感兴趣,

This llvm doc 是一个很好的起点。

现代异常处理确实是基于 table 且零成本的。不幸的是,Windows x86 - one of the most popular targets for game development. Most likely it was due to binary compatibility reasons but even Raymond Chen doesn't now the reason. In x64 they implemented 情况并非如此,应该从一开始就采取这种方式。