CppCoreGuidelines NR.3 不要避免异常
11 January 2024
“Don’t avoid exceptions”
理由
似乎有四个理由认为不应该用异常:
- 异常效率低
- 异常导致内存泄漏和错误
- 异常的性能不稳定
- 异常处理需要很多运行时空间
我们无法做到人人都满意。尽管,关于异常的讨论已经有 40 多年的历史了。有些语言甚至无法去掉异常单独使用,而另一些则不支持异常。这就导致了一些不同的传统,有的倾向于用异常,有的倾向于不用。然后互相争执不休。
然而,我们还是要简单讨论下为什么我们认为本指南认为编程里使用异常是最好的方案。简单的支持或反的的争论互相不相容。实际上,有一些应用场合中,其实是不建议使用异常的。比如没有可靠的运行时估算的异常是不能用于硬实时系统的。
考虑下反对异常的主要讨论:
- 异常效率低:相比于什么?我们要保证在进行比较的时候,要处理同一组错误,处理效果一样。如果一个程序遇到错误直接终止,而另一个仔细清理资源,然后记录一个错误日志。这就不能放在一起比较了。是的,有的系统的错误处理过程很差;有时候,这种系统强制我们用其他的错误处理方式,但是这不是异常的根本问题。任何情况,当我们在讨论效率问题的时候,一定要小心,我们是否有足够好的数据进行讨论。
- 异常导致内存泄漏和错误:不会的。如果你的代码是一个指针的耗子窝(a rat’s nest of pointers),没有一个全局的资源管理策略的话,不管你怎么做,都会出问题。如果你的系统中有成千上万行这样的代码,你可能都没办法用异常。但是,这里的问题是过度的、肆无忌惮的使用指针,而不是异常。我们认为,你需要 RAII 来保证基于异常的错误处理过程简单又安全。这时候,使用异常就比其他错误处理方式更简单更安全。
- 异常的性能不稳定:如果你运行硬实时系统,你必须保证在确定的时间结束任务,你需要工具支持这种实时保障。就我们所知,此类工具目前还没有(至少对于大多数程序员来说还没有)。
- 异常处理需要很多运行时空间:对于小的嵌入式系统来说可能存在这个问题。但是,在抛弃异常之前,请考虑下,用错误码的方式处理错误需要多少空间,没捕捉到错误会造成什么样的故障。
很多,可能是大部分的关于异常的问题,都是因为需要处理老旧混乱代码造成的。
支持使用异常的基本论断是:
- 他们清晰的分清错误的函数返回和普通的函数返回。
- 你无法忘记或忽略异常。
- 你可以系统的使用异常。
记住
- 异常用于报告错误(在 C++ 语言中),其他语言里异常可能有其他用处。
- 异常用于无法局部处理的错误。
- 不要尝试在每个函数中捕捉每个异常(那会很繁琐,笨拙,代码速度变慢)。
- 异常不用于因为某个无法恢复的错误而立即结束一个模块/系统。
其他方案
- RAII
- 合约/断言:用 GSL 的
Expects
和Ensures
,直到我们的语言支持合约。