此link个州,
要捕获异常,我们必须将一部分代码置于异常之下 检查。这是通过在try中包含该部分代码来完成的 块。当在该区块内出现异常情况时, 抛出异常将控件转移到异常 处理程序。如果没有抛出异常,代码将继续正常运行 所有处理程序都被忽略了。
这是否意味着由于在运行时“检查”的额外任务而使用try块会降低性能?
答案 0 :(得分:68)
TL; DR NO ,与错误代码处理相比,非异常路径上的异常通常更快。
嗯,显而易见的是与什么相比?
与不处理错误相比,它明显降低了性能;但是性能是否值得缺乏正确性?我认为它不是,所以让我们假设您的意思是与使用if
语句检查的错误代码进行比较。
在这种情况下,它取决于。有多种机制用于实现异常。实际上,它们可以通过一种非常接近if
语句的机制来实现,它们最终具有相同的成本(或略高)。
在C ++中,所有主要编译器(gcc在4.x系列中引入它,MSVC将其用于64位代码)现在使用零成本异常模型。如果您阅读了Need4Sleep链接到的technical paper,则会将其列为表驱动方法。这个想法是,对于程序的每个点,可能会抛出你在边表中注册一些零碎的东西,这将允许你找到正确的catch子句。老实说,它比旧策略更复杂一些,但零成本名称是由 free 引发的,不应该抛出任何异常。将此与CPU上的分支错误预测进行对比。另一方面,当抛出异常时,惩罚是巨大的因为表存储在冷区(因此可能需要往返RAM或更糟)...但例外情况很特别,对吗?
总而言之,使用现代C ++编译器,异常比错误代码更快,代价是更大的二进制文件(由于静态表)。
为了详尽无遗,还有第三种选择:堕胎。不是通过状态或异常传播错误,而是可以中止该过程。这仅适用于有限数量的情况,但它比任何一种情况都更好地优化。
答案 1 :(得分:6)
查看draft Technical Report on C++ Performance的第5.4节 这特别是关于c ++中try-catch语句的开销。
该部分的一些摘录:
5.4.1.1.2“代码”方法的时间开销
• On entry to each try-block
♦ Commit changes to variables enclosing the try-block
♦ Stack the execution context
♦ Stack the associated catch clauses
• On exit from each try-block
♦ Remove the associated catch clauses
♦ Remove the stacked execution context
• When calling regular functions
♦ If a function has an exception-specification, register it for checking
• As local and temporary objects are created
♦ Register each one with the current exception context as it is created
• On throw or re-throw
♦ Locate the corresponding catch clause (if any) – this involves some runtime check (possibly resembling RTTI checks)
If found, then:
destroy the registered local objects
check the exception-specifications of the functions called in-between
use the associated execution context of the catch clause
Otherwise:
call the terminate_handler6
答案 2 :(得分:2)
这取决于。对于异常处理,编译器必须执行某些操作 - 否则它无法进行堆栈展开等。这意味着是的,异常处理会降低性能 - 即使没有抛出异常。多少 - 这取决于您的编译器实现。
另一方面,你必须质疑自己:如果你自己插入错误处理代码,它真的会更快(测量它 - 不要猜测它)。它可以和异常一样(客户端不能忽略异常 - 错误代码可以 - 并且它们可以执行stackunwinding,错误代码不能)。此外,代码可以编写为更易于维护,但有例外。
简短:除非您的代码非常非常非常非常关键,否则请使用异常。即使你决定反对他们:先测量。规则的一个例外:在模块边界或析构函数中抛出异常是个坏主意。
答案 3 :(得分:2)
这实际上取决于具体的编译器。
如果编译器更喜欢考虑异常抛出一个非常特殊的条件,那么你可以实现一个方案,在没有异常的情况下你有零开销,但反过来,如果出现异常和/或更多代码大小。
要实现零开销方法,您可以注意到在C ++中,您无法动态更改代码,因此一旦您知道堆栈帧和返回地址是什么,就可以修复在展开的情况下必须销毁的对象是什么?有一个异常处理代码部分。因此,抛出异常的代码可以检查所有函数调用站点的全局表,以决定应该做什么。
另一方面,通过准备要显式销毁的对象列表以及正常执行期间异常处理代码的地址,可以更快地使异常抛出。这将使常规代码变慢,但异常处理速度更快,而且我会说代码更小。
不幸的是,C ++中没有标准的方法来完全放弃异常支持,所以必须要付出这样的可能性:标准库抛出异常和任何调用未知代码的代码(例如使用函数指针或调用虚拟代码)方法)必须准备好处理异常。
答案 4 :(得分:1)
我建议在执行内存分配,删除,调用另一个复杂函数等的函数中添加try catch。实际上,性能方面的尝试catch会增加一些开销。
但考虑到捕捉未知异常的优点,这是非常有帮助的。 良好的编程习惯总是建议在代码中添加某种异常处理,除非您是一位优秀的程序员。
我想知道为什么你这么担心小的性能问题而不是整个程序遇到异常。