快捷搜索:

了解C++异常处理的系统开支

为了在运行时处置惩罚非常,法度榜样要记录大年夜量的信息。无论履行到什么地方,法度榜样都必须能够识别出假如在此处抛出非常的话,将要被开释哪一个工具;法度榜样必须知道每一个进口点,以便从try块中退出;对付每一个try块,他们都必须跟踪与其相关的catch子句以及这些catch子句能够捕获的非常类型。这种信息的记录不是没有价值的。确保法度榜样满意异老例格不必要运行时的对照(runtime comparisons),而且当非常被抛出时也不用额外的开销来开释相关的工具和匹配精确的catch字句。然则非常处置惩罚确是有价值的,纵然你没有应用try,throw或catch关键字,你同样得付出一些价值。

让我们先从你不应用任何非常处置惩罚特点也要付出的价值谈起。你必要空间建立数据布局来跟踪工具是否被完全构造(constructed)(参加条目10),你也必要系统光阴维持这些数据布局赓续更新。这些开销一样平常不是很大年夜,然则当采纳不支持非常的措施编译的法度榜样一样平常比支持非常的法度榜样运行速率更快所占空间也更小。

在理论上,你不能对此进行选择:C++编译器必须支持非常,也便是说,当你不用非常处置惩罚时你不能让编译器临盆商打消这方面的开销,由于法度榜样一样平常由多个自力天生的目标文件(object files)组成,只有一个目标文件不进行非常处置惩罚并不能代表其他目标文件不进行非常处置惩罚。而且纵然组成可履行文件的目标文件都不进行非常处置惩罚,那么还有它们所连接的法度榜样库呢?假如法度榜样的任何部分应用了非常,其它部分必须也支持非常。否则在运行时法度榜样就弗成能供给精确的非常处置惩罚。

不过这只是理论,实际上大年夜部分支持非常的编译器临盆商都容许你自由节制是否在天生的代码里包孕进支持非常的内容。假如你知道你法度榜样的任何部分都不应用try,throw或catch,并且你也知道所连接的法度榜样库也没有应用try,throw或catch,你就可以采纳不支持非常处置惩罚的措施进行编译,这可以缩小法度榜样的尺寸和前进速率,否则你就得为一个不必要的特点而付出价值。跟着光阴的推移,应用异处置惩罚的法度榜样库开始变得普遍了,上面这种措施将徐徐不能应用,然则根据今朝的软件开拓环境来看,假如你已经抉择不应用任何的非常特点,那么采纳不支持非常的措施编译法度榜样是一个机能优化的合理措施。同样这对付想避开非常的法度榜样库来说也是一个机能优化的好措施,这能包管非常不会从客户端法度榜样通报进法度榜样库里,不过同时这样做也会阴碍客户端法度榜样重定义法度榜样库中声明的虚拟函数,并不容许有在客户端定义的回调函数。

应用非常处置惩罚的第二个开销来自于try块,无论何时应用它,也便是无论何时你想能够捕获非常,那你都得为此付出价值。不合的编译器实现try块的措施不合,以是编译器与编译器间的开销也不一样。粗略地预计,假如你应用try块,代码的尺寸将增添5%-10%并且运行速率也同比例减慢。这照样假设法度榜样没有抛出非常,我这里评论争论的只是在法度榜样里应用try块的开销。为了削减开销,你应该避免应用无用的try块。

编译器为异老例格天生的代码与它们为try块天生的代码一样多,以是一个异老例格一样平常花掉落与tyr块一样多的系统开销。什么?你说你觉得异老例格只是一个规格而已,你觉得它们不会孕育发生代码?那么好,现在你应该对此有新的熟识了。

现在我们来到了问题的核心部分,看看抛出非常的开销。事实上我们不用太关心这个问题,由于非常是很少见的,这种事故的发生每每被描述为exceptional(非常的,罕有的)。80-20规则(拜见条目16)奉告我们这样的事故不会对全部法度榜样的机能造成太大年夜的影响。然则我知道你仍然好奇地想知道假如抛出一个非常到底会有多大年夜的开销,谜底是这可能会对照大年夜。与一个正常的函数返回比拟,经由过程抛出非常从函数里返回可能会慢三个数量级。这个开销很大年夜。然则仅仅当你抛出非常时才会有这个开销,一样平常不会发生。然则假如你用非常表示一个对照普遍的状况,例如完成对数据布局的遍历或停止一个轮回,那你必须从新予以斟酌。

不过请等一下,你问我是怎么知道这些工作的呢?假如说支持非常对付大年夜多半编译器来说是一个较新的特点,假如说不合的编译器非常措施也不合,那么我若何能说法度榜样的尺寸将增大年夜5%-10%,它的速率也同比例减慢,而且假如有大年夜量的非常被抛出,法度榜样运行速率会呈数量级的减慢呢?谜底是令人惶恐的:一些传闻和一些基准测试(benchmarks)(拜见条目23)。事实是大年夜部分人包括编译器临盆商在非常处置惩罚方面险些没有什么履历,以是只管我们知道非常确凿会带来开销,却很难猜测出开销的准确数量。

审慎的措施是对本条目所论述的开销有懂得,然则不追究详细的数量。(即定性不定量 译者注)不论非常处置惩罚的开销有多大年夜我们都得坚持只有必须付出时才付出的原则。为了使你的非常开销最小化,只要可能只管即便就采纳不支持非常的措施编译法度榜样,把应用try块和异老例格限定在你确凿必要它们的地方,并且只有在确为非常的环境下(exceptional)才抛出非常。假如你在机能上仍然有问题,总体评估一下你的软件以抉择非常支持是否是一个起感化的身分。假如是,那就斟酌选择其它的编译器,能在C++非常处置惩罚方面具有更高实现效率的编译器。

您可能还会对下面的文章感兴趣: