CppCoreGuidelines E.30 不要使用异常规格说明
15 August 2023
“Don’t use exception specification”
理由
异常规格说明导致错误处理变的很脆弱,引起额外的运行时开销。所以这个功能已经从标准 C++ 中移除了。
例子
int use(int arg) throw(X, Y) { // ... auto x = f(arg); // ... }
如果 f()
抛出的异常不属于 X
或 Y
就会调用到未定义的出错处理过程,默认的行为是程序终止。这样看起来没问题,但是如果我们修改了 f()
,让它抛出
Z
异常,这时候,我们的 use
会因为 Z
异常而终止,除非我们修改 use()
的异常规格说明,这时候可能还需要重新测试所有代码。困难的地方是,这个 f()
函数可能是我们无法控制的程序库函数,它抛出的新的异常 use()
可能不关心、也不知道怎么处理。这时候,我们可以修改 use()
函数,让它把新的异常 Z
转交给调用 use()
的函数来处理。但是这时候,调用 use()
的函数可能需要修改了。很快,这个事情就会变的很不可控。我们也可以在 use()
中 try-catch
捕捉 Z
异常。但是这个方法也很快变的难以管理。请注意,修改总的异常种类可能涉及到系统的最底层。比如修改某些网络库或者中间件。所以,这些修改会像肥皂泡一样,一直上升到调用链的最上面。在大的代码库中,这就意味着,只有最后一个用户修改了代码之后,整个代码库才可以切换到最新版本的库。如果
use()
属于程序库,可能会因为某些未知的客户在使用,我们就无法升级它。
“让异常一直传递到某个能处理的函数”,这个策略多年来一直证明是有效的方法。
注意
用异常规格说明的方式静态地进行强化实际上并无益处。
注意
如果没有异常要抛出,请使用 noexcept
强化
标记出现异常规格说明的地方。