2016-02-12 43 views
11

在更高效的C++(第15号)一书中,我发现如果启用了异常,代码将变得非常慢,即使它们未被使用。在我看来,例外是有限的使用,我尽量避免它们,但这是另一个话题。如何关闭异常处理?

我不完全理解他的说法:

  1. 是什么启用/禁用异常是什么意思?它是有零还是多于零的try/catch块之间的区别?它是一个编译器标志吗?如果我使用可能发生异常的DLL,会发生什么情况?
  2. 假设没有异常被丢进:
    • 代码是否变得更慢作为一个整体或者是只有当程序进入零件/退出try/catch块变慢?据作者说,两者都是事实。
  3. 我该如何编译没有例外?我可以做到这一点,即使我有try/catch块吗?如果我使用的DLL可能会引发异常,我可以这样做吗?
+1

这本书很旧,编译器从此变得更聪明。今天体面的一个可以做到零开销,使用指令地址的基于表的查找来查找堆栈解开时需要运行的代码。但是,如果您想要了解它,然后查看编译器选项,大多数都可以选择禁用该功能。 –

+0

“在我看来,例外是有限的使用,我尽量避免它们,但这是另一个话题。”我的猜测是你的代码不会调用任何可能的系统调用。你正在编程CPU加热器吗? – 2016-03-08 18:22:17

+0

@ user4590120:异常并不是处理故障的唯一方法。我使用返回代码来检查成功或失败。 – Fabian

回答

6

启用/禁用异常是什么意思?

将标志传递给编译器,该标志禁用与异常有关的标准一致性,并且不会产生任何异常支持。

如果我使用可能发生异常的DLL,会发生什么情况?

如果某个库在内部处理异常,则为空。如果它让它逃到调用者(由于ABI问题,我从来没有见过任何这样做的库,但无论如何),你的程序崩溃(最好的情况),因为它无法处理它。如果您的代码包含的DLL包装器将错误代码转换为异常(常见事件),那么它与您在代码中使用异常的情况相同。

代码整体变慢还是只是程序进入/退出try/catch块变慢的部分?据作者说,两者都是事实。

请注意,你所引用的书是旧的。编译器正在发展。现代编译器使用零成本异常,如果不抛出异常,则不会导致性能成本。异常处理确实使可执行文件变得更大,因为它应该生成处理异常所需的所有数据和代码,但不应使其在非例外路径上变慢。

我如何编译没有例外?我可以做到这一点,即使我有try/catch块吗?

你以编译器特定的方式做到这一点。请查阅你的编译器文档通常这样做会使编译器拒绝包含任何异常相关设施的代码,例如指出try为无法识别的标识符。

+1

“异常处理确实使可执行文件更大” - 比什么更大?具有错误返回值的等效程序也需要代码和数据来处理这些。例外的一大优点是,错误处理代码和数据最初可以留在磁盘上,这样您的程序就可以更快地启动。 – MSalters

+0

“它不应该让它在非常规路径上变慢” - 实际上,现代异常处理使得非错误路径_faster_。这是因为编译器可以识别并优化该路径。由于错误返回值,编译器不知道是否优化“== 0”或“!= 0”返回值,因为不同的函数使用不同的返回值约定。 – MSalters

+1

@MSalters比完全相同的代码编译时没有异常支持(这意味着原始代码必须没有异常处理)。这样就避免了标准库的异常处理(例如,'new'通常会变成nothrow'new',例如用空指针访问崩溃来代替'bad_alloc'异常) –