异常一直是 C++ 中争议较大的语言特性。是否应该在项目中使用或禁用异常,应该是 C++ 开发者中讨论得最激烈的话题了——其拥护者和反对者都表现出较强的态度。
在著名的 Google C++ Style Guide [1]中,关于异常的一节[2],明确禁用 C++ 异常:
We do not use C++ exceptions.
禁用异常的主要原因是 Google 的历史包袱太重了,代码库中有很多旧风格的 C++ 代码对异常不友好,根本没考虑异常,做不到异常安全。
On their face, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has implications on all dependent code. If exceptions can be propagated beyond a new project, it also becomes problematic to integrate the new project into existing exception-free code. Because most existing C++ code at Google is not prepared to deal with exceptions, it is comparatively difficult to adopt new code that generates exceptions.
LLVM Coding Standards[3] 中也禁止使用异常:
In an effort to reduce code and executable size, LLVM does not use exceptions or RTTI...
不过,LLVM 在创立之初并没有历史包袱,禁用异常的原因是异常让最终的二进制文件大小增加了不少——异常产生的位置决定了需要如何做栈展开(stack unwinding),这些数据需要存储在表里——这就是异常导致二进制较大的主要原因。
也有一些支持使用 C++ 异常的编码指南,比如 Bjarne Stroustrup(C++ 之父) 和 Herb Sutter 维护的 CppCoreGuidelines [4]中就旗帜鲜明地支持使用异常。可以参考 CppCoreGuidelines 中关于错误处理[5]的一节。
isocpp[6] 网站上,也有一个 FAQ 专门解释为什么应该使用异常:Exceptions and Error Handling[7]。
异常的好处很明显:
__attribute__((warn_unused_result))
, C++17 开始也支持 [[nodiscard]]
属性,但是从实践中看来,这些功能的使用目前并不普及。if xxx else yyy
确实很难受,也很干扰正常逻辑。异常带来的问题也很多:
错误码和异常是两种不同的错误处理风格,使用错误码或异常其实各有优劣。C++ 没有强制开发者只能使用其中一种,重要的是在团队和项目中保持统一。个人认为,在一般团队中,要用好异常还是有一定挑战的。
Google C++ Style Guide : https://google.github.io/styleguide/cppguide.html
[2]关于异常的一节: https://google.github.io/styleguide/cppguide.html#Exceptions
[3]LLVM Coding Standards: https://llvm.org/docs/CodingStandards.html#do-not-use-rtti-or-exceptions
[4]CppCoreGuidelines : http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
[5]错误处理: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-errors
[6]isocpp: https://isocpp.org/
[7]Exceptions and Error Handling: https://isocpp.org/wiki/faq/exceptions