本文转载自http://www.jztop.com/dev/32/cc/a116123241932071.html
为了在运行时处理异常,程序要记录大量的信息。无论执行到什么地方,程序都必须能够识别出如果在此处抛出异常的话,将要被释放哪一个对象;程序必须知道每一个入口点,以便从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++异常处理方面具有更高实现效率的编译器。
分享到:
相关推荐
然而,由于其设计初衷是为了操作系统层面的异常处理,所以在应用层面上,SEH往往与C++的高级语言特性(如对象生命周期管理)不兼容。 ### C++异常处理与Win32 SEH的结合 尽管C++异常处理和Win32 SEH各有优势,但在...
3. 标准 C++异常处理的基本语法和语义 4. 实例剖析 EH 5. C++的 new 和 delete 操作时的异常处理 6. Microsoft 对于的实现版本中的异常处理 7. 部分构造及 placement delete 8. 自动删除,类属 new 和 delete、...
c++异常处理课件,可以看看,c++异常处理练习
异常处理是C++中一个至关重要的主题,它帮助开发者编写出更加健壮、易于维护的代码,特别是在大型系统中,异常处理能够保证程序在面对错误时具有更好的恢复能力。了解并熟练应用异常处理机制,是每个C++程序员必备的...
通过阅读和运行这些代码,你可以更深入地了解如何在实际项目中应用C++的异常处理和Windows的SEH。 总之,理解和熟练掌握C++的异常处理机制,以及在VS环境下如何结合使用SEH,对于编写健壮、容错性好的程序至关重要...
c++异常处理实现标准c++异常处理实现标准
首先,C++异常是通过类型系统进行传播的,而C#异常是对象。为了在C#中处理C++异常,我们需要使用`extern "C"`和`System::Runtime::InteropServices`命名空间中的特性来定义接口和方法。例如: ```csharp using ...
异常处理是C++中用于处理程序运行时错误的一种机制。它允许程序员在可能出现错误的地方抛出异常,然后在程序的其他部分捕获并处理这些异常,而不是依赖于返回错误代码。这种设计使得错误处理代码与正常流程分离,...
下面将详细阐述C++异常处理的基本概念、使用方法以及与其他语言或系统的异常处理机制的对比。 1. **异常处理框架** - 在C++中,异常处理通过`try`、`catch`和`throw`关键字进行。`try`块包含可能抛出异常的代码,...
14.1 异常处理概述 14.2 C++异常处理的实现 14.2.1 异常处理的语法 14.2.2 捕获所有类型的异常 14.2.3 带有异常说明的函数原型 14.3 异常处理中对象的构造与析构
标准C++异常处理的基本语法和语义 4. 实例剖析 5. C++的new 和delete 操作时的异常处理 6. Microsoft 对于的实现版本中的异常处理 7. 部分构造及placement delete 8. 自动删除,类属new 和delete、placement ...
总的来说,C语言的异常处理更依赖于操作系统,主要用于硬件级别的异常,而C++的异常处理是语言内置的,更适用于逻辑错误和异常安全编程。在实际开发中,理解这两种机制的区别对于编写健壮的程序至关重要。
该代码给出了基本的异常处理操作(throw catch等),用C++实现
微软还对C和C++的异常处理进行了扩展,引入了结构化异常处理(Structured Exception Handling, SEH),这使得C和C++程序能够处理更广泛的异常情况,而MFC的异常处理则主要针对C++。 异常处理的核心流程包括以下几个...
C++ 文件打开异常处理:检查文件是否正常打开,如果文件不存在,或者无法打开,就抛出异常,输出错误信息。
图像处理系统是一个典型的图像处理软件,它由图像显示、图像转换、图像处理、字符识别、其他和帮助等几部分组成。 图像显示模块 该模块主要包括显示位图、显示JPEG、显示GIF 3个部分。 图像转换模块 该模块...
本文将深入探讨C++在图书馆管理系统中的应用以及异常处理在系统设计中的重要性。 一、C++语言基础 C++是一种面向对象的编程语言,它的特点是性能高、灵活性强,特别适合开发大型、复杂的系统。在图书馆管理系统中...
简单,易懂的方式讲解C++与java异常处理的方法,两者的异同
C++异常处理是一种强大的错误处理机制,它允许程序员在程序执行过程中通过`throw`语句抛出异常,然后在...了解编译器的这种实现方式,有助于开发者更好地理解和利用C++的异常处理特性,编写出更加健壮和可靠的代码。