exception - 为什么异常处理不好?

标签 exception error-handling error-reporting

Google 的 Go 语言没有异常(exception)作为设计选择,而 Linux 名人 Linus 则称异常(exception)为垃圾。为什么?

最佳答案

异常使编写代码变得非常容易,其中抛出的异常将破坏不变量并使对象处于不一致的状态。它们本质上迫使您记住,您所做的大多数语句都可能会抛出错误,并正确处理它。这样做可能会很棘手并且违反直觉。

考虑这样一个简单的例子:

class Frobber
{
    int m_NumberOfFrobs;
    FrobManager m_FrobManager;

public:
    void Frob()
    {
        m_NumberOfFrobs++;

        m_FrobManager.HandleFrob(new FrobObject());
    }
};

假设FrobManager删除FrobObject,这看起来没问题,对吧?或者也许不是……想象一下,如果 FrobManager::HandleFrob()operator new 抛出异常。在此示例中,m_NumberOfFrobs 的增量不会回滚。因此,任何使用 Frobber 实例的人都将拥有一个可能已损坏的对象。

这个例子可能看起来很愚蠢(好吧,我不得不花点力气来构造一个:-)),但是,要点是,如果程序员没有不断地考虑异常,并确保每个排列每当有抛出时,状态就会回滚,这样你就会遇到麻烦。

举个例子,您可以像考虑互斥体一样来考虑它。在关键部分内,您依靠多个语句来确保数据结构没有损坏并且其他线程无法看到您的中间值。如果这些语句中的任何一个没有随机运行,那么您最终会陷入痛苦的世界。现在去掉锁和并发,并像这样思考每个方法。如果愿意的话,可以将每个方法视为对象状态的排列事务。在方法调用开始时,对象应该处于干净状态,并且在结束时也应该处于干净状态。在这之间,变量 foo 可能与 bar 不一致,但您的代码最终会纠正这一点。异常(exception)意味着你的任何一个陈述都可以随时打断你。在每个单独的方法中,您有责任确保其正确并在发生这种情况时回滚,或者对您的操作进行排序,以便抛出不会影响对象状态。如果你弄错了(而且很容易犯这种错误),那么调用者最终会看到你的中间值。

诸如 RAII 之类的方法(C++ 程序员喜欢将其称为此问题的最终解决方案)可以在很大程度上防止这种情况发生。但它们并不是 Elixir 。它将确保您在抛出时释放资源,但不会让您不必考虑对象状态的损坏和调用者看到中间值。因此,对于很多人来说,根据编码风格,没有异常(exception)更容易说。如果限制所编写的代码类型,就更难引入这些错误。如果不这样做,就很容易犯错误。

整本书都是关于 C++ 中的异常安全编码的。很多专家都搞错了。如果它真的那么复杂并且有那么多细微差别,也许这是一个好兆头,表明您需要忽略该功能。 :-)

关于exception - 为什么异常处理不好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1736146/

相关文章:

ruby-on-rails - 如何测试变量未定义或RSpec中引发异常

php - mysqli_fetch_assoc()需要参数/调用成员函数bind_param()错误。如何获取并修复实际的mysql错误?

maven - EOF异常: Input contained no data in cmd

Java异常的正确使用和代价

java - 使用 "setUncaughtExceptionHandler"和 "Toast"的全局异常处理

javascript - MSoft是否为MVC3应用程序使用的服务器端错误插件或工具提供持久的客户端错误报告?

error-reporting - 如何关闭PHP + MySQL错误格式化

c# - 使用保护子句或捕获异常更好吗?

bash - Bash中的错误处理

node.js - 如果路由未知,Express.js会忽略SyntaxError