一般来说,我倾向于对具有多个故障点的代码使用 try/catch,并且这些故障点有一个公共处理程序。
根据我的经验,这通常是在执行某些操作之前验证输入或上下文或在执行某些操作后验证输出的代码。
我从文献和同事那里得到了建议,以尽量减少这些块中的代码,我接受这通常是好的建议。
我想更多地了解上述建议的基础:
在 C++ 中,成本取决于实现。一般来说,异常的实现有两种方式:
第一个是“表”方式。编译器构建一组表来查找抛出异常的位置以及去往何处。当抛出异常时,它必须搜索调用堆栈中的每个表,直到找到可以捕获此异常的内容。由于这都是基于运行时的,因此进入或退出 try catch 不会产生任何惩罚(很好),但抛出异常可能涉及许多查找,从而产生更慢的抛出。我个人更喜欢不必为 try catch 块付费,因为异常应该是一种非常罕见的情况。如果可执行文件必须存储表,这也会使可执行文件变得更大。
秒是“代码”方法。从概念上讲,每次代码进入 try catch 块时,该块的位置都会被推送到堆栈上。这会在进入和退出 try-catch 块期间产生成本,但是,当引发异常时,运行时机制可以快速从堆栈中弹出以找到去向。因此,抛出异常(快得多?)更快,但进入块现在是有成本的。将 try catch 块放入紧密的低级循环中可能会产生显着的开销。
您必须检查您的特定编译器以了解它们使用的是哪一个。
我发现了有关 C++ 性能的技术报告(pdf 警告),其中包含有关异常的部分。你可能会觉得很有趣。我有同事认为 try/catch 块中的每条指令都有开销,但这份技术报告似乎并不支持这个想法。
取决于编译器。为什么不编写一个带有 try-catch 块的简单函数和一个不带 try-catch 块的类似函数并比较生成的机器代码?
我发现 C++ FAQ 网站和相应的书籍对此事有启发性的讨论。
根据我的经验,try/catch 块的最大问题是我们经常尝试过于笼统地捕获异常。例如,如果我用一个捕获 (...) 的 try/catch 块包装我的主函数,我基本上是在尝试不允许我的程序因抛出的异常而崩溃。
我认为这种方法的问题有两个。 1)当我测试和调试时,我没有看到任何错误,也没有机会修复它们。 2)这确实是一种偷懒的方式。我没有思考可能出现的问题并找出边缘情况是什么,而是努力避免失败。努力不失败与努力成功有很大不同。
在大多数语言中,通过普通方法进入和退出 try/catch 块是免费的,只有当抛出异常时,异常处理程序才会查找处理异常的位置。
在 C++ 中,不应使用 try/catch 块来执行清理。相反,您可能希望使用模板来执行资源获取。
auto_ptr 是一个[坏]例子
同步锁,将互斥锁存储为状态变量,并使用局部变量(模板或常规类)来执行 .acquire()/.release() 方法。
您执行的操作越多,您就越不用担心在异常情况下手动释放对象。 C++ 编译器会为你做这件事。