【问题标题】:C++ Exceptions; int or std::exception?C++ 异常; int 还是 std::exception?
【发布时间】:2011-08-07 23:23:30
【问题描述】:

我正在编写一些需要进行错误报告的库函数。我想使用异常而不是返回值。

我编写了引发 int 异常的函数。

例如:

if(strm->atEnd()){
    // unexpected end of stream
    throw -2;
}

我的问题是,这种方法可以吗?还是应该抛出从 std::exception 派生的异常?

以什么方式抛出 std::exception 更好? (除了能够使用 catch(std::exception &e))

抛出 int 异常是不好的做法吗? (所有 throw int 值都记录在 doxygen cmets 中)

我找不到任何理由说明为什么(在这种情况下)我应该扔一个物体。

【问题讨论】:

  • 当我一起破解东西时,我可能会这样做。但是当我完成时,它总是会生成一个真正的异常对象(源自 std::rtuntime_error)。因为这简化了我所有的异常处理代码。假设你在 main() 中捕捉到了它。你怎么知道哪个组件产生了错误-345678?

标签: c++ exception


【解决方案1】:

我会根据std::exception 抛出异常。

throw std::runtime_error("unexpected end of stream")

我发现这更容易catch、记录、等等。它还允许从代码中删除注释和幻数。

然后可以将此消息发送给最终用户,让他们有希望解决问题。

用户和图书馆消费者无法阅读代码中的 cmets,他们也不太可能知道“-2”是什么意思。

【讨论】:

    【解决方案2】:

    异常适用于异常行为。它们是您最不应该担心的优化问题!

    唐纳德·高德纳说:

    我们应该忘记小的效率,比如大约 97% 的时间:过早的优化是万恶之源

    此外,作为异常的对象可能会携带有关错误的信息。

    例如,您有一个异常,表示无法读取文件。如果您抛出一个对象异常,该对象可能带有文件名,而 ints 则不能。

    如果异常来源未知(在您的堆栈深处)并且没有人捕获它,那么如果异常是具有适当信息的对象,则调试程序会更容易。

    【讨论】:

      【解决方案3】:

      我的问题是,这种方法可以吗?

      考虑可读性。不会

      throw CUnexpectedEndOfStream();
      

      更具可读性
      throw -2
      

      ?

      在很多情况下,调试器中不会看到抛出的 CUnexpectedEndOfStream 实例意味着 TONS 超过 -2。更不用说 CUnexpectedEndOfStream 可以存储有关问题的大量有用信息,例如无法读取的文件以及有关问题性质的更多信息。

      或者我应该抛出从 std::exception 派生的异常吗?

      如果您选择以这种方式组织其他异常,则从 std::exception 继承可能会有所帮助。它是客户端代码可以使用的方便的基类。还取决于您可能想要使用的例外情况std::runtime_error

      抛出 int 异常是不好的做法吗? (所有 throw int 值都记录在 doxygen cmets 中)

      谁说这是不好的做法?抛出异常是处理异常情况的好方法。我抛出的大多数异常都是因为客户端代码可以阻止某些事情,因为我的代码的用户违反了合同。但也存在许多其他异常的非正常情况,例如操作系统错误、磁盘已满等。所有不属于您的程序正常流程的事情。更重要的是,因为它们不是一部分您的程序的正常流程,您不必担心性能。

      举个例子,我曾经使用异常来触发某个消息解析失败。但是,我发现这些解析错误经常发生,以至于我开始处理异常并修复问题输入和重新解析。一段时间后,我意识到一个更具可读性的解决方案是直接在解析代码中解决问题,不再将其视为例外情况。做出解析决定的所有代码都被放回了一个地方,我不会像喝醉的水手扔脏话那样抛出异常。

      【讨论】:

      • ISTM 他特别询问有关抛出 int 异常
      【解决方案4】:

      你应该抛出一个从 std::exception 派生的异常,例如std::runtime_error.

      大多数现有代码都假定普通 C++ 异常是 std::exception,而其他任何东西都是“硬异常”,可以传播到非常高的控制级别,例如 main

      例如,现有代码很可能无法为您的int 记录任何合理的消息。它只是“未知的异常类型”。

      干杯,

      【讨论】:

        【解决方案5】:

        你为什么不这样做:

        if(strm->atEnd()){
            // unexpected end of stream
            throw std::exception("-2");
        }
        

        throw -2 不好,因为-2 的类型既不是std::exception,也不是派生自std::exception

        或者你最好把你自己的类写成:

        class FileException : public std::exception
        {
              //...
        };
        

        然后

         throw FileException("Unexpected end of stream");
        

        这更易读。

        【讨论】:

        • 就我个人而言,我已经停止派生自己的异常类(我只使用 std::runtime_error);除非有特殊情况我可以用专门的异常来捕捉和纠正。如果我所能做的就是记录,那么 std::runtime_error 通常是完美的选择。注意:FileException 可能应该从 std::runtime_error 派生(因为 std::exception 没有接受错误消息的构造函数)子注意:MS 对 std::exception 有一个非标准扩展,允许您传递错误消息.
        • 你到底为什么要保留“-2”却把它作为例外原因?
        • @LightnessRacesinOrbit:我不在乎“价值”。在这个答案中,我只关心“类型”..即throw "Unexpected end of stream" 仍然很糟糕。所以抛出直接或间接派生自 std::exception 的类型的异常。
        猜你喜欢
        • 1970-01-01
        • 2011-02-03
        • 1970-01-01
        • 2014-04-23
        • 2011-05-16
        • 2014-01-25
        • 1970-01-01
        • 2010-09-25
        • 2018-01-12
        相关资源
        最近更新 更多