潜在的异常会带来开销吗?

时间:2009-12-02 17:14:25

标签: c++ performance exception overhead

如果没有抛出异常,那么可能抛出异常的代码会比没有代码的类似代码性能下降吗?

9 个答案:

答案 0 :(得分:4)

已经证明,可以在“正常”(非异常相关)代码中实现零开销的C ++异常处理机制。但是,在实践中,编译器通常坚持使用更简单的实现,这通常会导致效率较低的“普通”代码。编译器必须考虑潜在异常在函数层次结构中飞行的可能性,因此如果抛出异常,则会生成一些额外的家庭操作以启用正确的堆栈展开。无论是否抛出异常,这个额外的家庭代码都会影响代码的整体效率。

这都是QoI(实施质量)问题。它是特定于编译器的。检查编译器以获取更多详细信息有些编译器实际上提供了启用/禁用C ++异常的选项,以便在根本不使用异常时生成最有效的代码。

答案 1 :(得分:3)

取决于;基于表的实现(我相信现代g ++使用的,以及Windows中用于x64二进制文件的策略)是非抛出异常的零处理开销(以稍微多一点的内存使用为代价)。基于函数的异常处理(x86 Windows使用)即使对于非抛出异常也会产生小的性能损失。

答案 2 :(得分:1)

尝试便宜,捕获便宜,扔贵。显然有一些额外的处理执行代码包含在try中。

对特殊事物使用例外 - 然后开销无关紧要。

答案 3 :(得分:1)

这取决于您的编译器。一些编译器/运行时组合在使用catch处理程序进入块时会做额外的工作。其他人构建静态数据结构,所有工作都在throw时发生。在所有情况下,进入成本都低于抛出,但是您希望对内部循环中的catch块保持谨慎。使用您关心的编译器测量时间成本。

答案 4 :(得分:1)

这取决于编译器,但答案几乎肯定是“是”。具体来说,如果范围包含具有非平凡析构函数的对象,则该对象将需要向运行时注册,以便在异常上调用析构函数。例如:

struct Thing
{
    ~Thing();
    void Process();
};

for (int i = 0; i < 1000000; ++i)
{
    Thing thing;
    thing.Process();
}

除了构建和处理一百万件事物之外,这还会产生一百万个函数调用来注册和取消注册每个Thing,以防对Process的调用抛出。

除此之外,当进入或离开try块时,开销很小,因为相应的catch块被添加到异常处理程序堆栈中或从异常处理程序堆栈中删除。

答案 5 :(得分:1)

由于编译器需要生成在抛出异常时将在inwind堆栈中生成的代码,因此在幕后添加了一些代码。但是,如果它更多,那么它是值得商榷的:

  • 生成的代码,用于在变量超出范围时自动调用析构函数,

  • 以及您必须编写的代码,以检查每个调用的退出状态并处理错误。

捕获错误的代价很高:尝试...捕获语句以及抛出异常时会发生什么:

  • 保留有关每个地方的信息,其中添加了try ... catch(也隐含地添加了例如析构函数或异常规范),

  • 很多用于放松的堆栈(以及用于调用的析构函数),看起来像是简单的跳转,

  • 将抛出的异常与catch()子句匹配,

  • 复制例外。

答案 6 :(得分:0)

与没有异常处理的代码相比,具有异常处理的Ya代码更慢,也更大。

因为当异常被提升时,它必须在堆栈展开过程中对要被破坏的对象进行簿记。

答案 7 :(得分:0)

无论它是否“在没有抛出异常时都可以实现零开销”以及所有理论讨论,现实情况是,对于某些编译器(g ++ 4.4),即使使用-O2优化,也只是你有一个抛出的事实在一个紧凑的循环函数(即 cpu-bound )中的子句会使函数放慢10到100倍之间的速度,这就是catch:这是抛出的时候实际上从来没有执行。

所以我的建议是避免像瘟疫这样的c ++中的标准异常处理(除非你证明我错了);如果要在性能敏感的应用程序上进行错误处理,请使用boost.context

答案 8 :(得分:0)

draft Technical Report on C++ Performance的第5.4节完全专注于异常的开销。