C++核心准则E.30:不要使用抛异常声明

时间:2022-07-23
本文章向大家介绍C++核心准则E.30:不要使用抛异常声明,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

E.30: Don't use exception specifications

E.20:不要使用抛异常声明

Reason(原因)

Exception specifications make error handling brittle, impose a run-time cost, and have been removed from the C++ standard.

抛异常声明让错误处理更脆弱,强制产生运行时成本,已经从C++标准中被移除了。

Example(示例)

int use(int arg)
    throw(X, Y)
{
    // ...
    auto x = f(arg);
    // ...
}

If f() throws an exception different from X and Y the unexpected handler is invoked, which by default terminates. That's OK, but say that we have checked that this cannot happen and f is changed to throw a new exception Z, we now have a crash on our hands unless we change use() (and re-test everything). The snag is that f() may be in a library we do not control and the new exception is not anything that use() can do anything about or is in any way interested in. We can change use() to pass Z through, but now use()'s callers probably needs to be modified. This quickly becomes unmanageable. Alternatively, we can add a try-catch to use() to map Z into an acceptable exception. This too, quickly becomes unmanageable. Note that changes to the set of exceptions often happens at the lowest level of a system (e.g., because of changes to a network library or some middleware), so changes "bubble up" through long call chains. In a large code base, this could mean that nobody could update to a new version of a library until the last user was modified. If use() is part of a library, it may not be possible to update it because a change could affect unknown clients.

如果f()抛出了不同于X和Y的异常,就会激活意外的错误处理,而这个处理的默认动作就是终止程序。那样还好,假设我们已经检查过了,这种事情不会发生,这时如果f被修改为抛出一个新异常Z,系统马上就会发生崩溃,除非我们修改use()(并且重新进行完整测试)。麻烦在于f()可能处于某个我们无法控制的功能库中,而且对于新异常use()也没有什么可做的,或者根本就不感兴趣。我可以修改use()将Z传出,但是接下来user()的调用者可能需要跟着修改。情况很快就会失控。或者我们可以为use()增加try-catch结构将Z映射到一个可以接受的异常。情况很快会再次失控。注意成组修改异常经常发生在系统的底层(例如由于网络库或某个中间件发生变化),因此变更会像气泡一样向上传递至整个调用链。在大规模代码中,这可能意味着没有人可以将库更新到新版本,直到最后的调用者发生变更。如果use()是库的一部分,它可能无法更新,因为这种变更不知道会影响谁。

The policy of letting exceptions propagate until they reach a function that potentially can handle it has proven itself over the years.

让异常传播直至一个有可能处理它的函数,这样的原则已经证明自己很多年了。

Note(注意)

No. This would not be any better had exception specifications been statically enforced. For example, see Stroustrup94.

没有。坚持推进使用抛异常声明一点好处也没有。参见

Stroustrup. The Design and Evolution of C++ (Addison-Wesley, 1994).

Note(注意)

If no exception may be thrown, use noexcept or its equivalent throw().

如果不会抛出任何异常,使用noexcept或者和它等价的throw()

Enforcement(实施建议)

Flag every exception specification.

标记所有的抛出异常声明。

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#e30-dont-use-exception-specifications