【问题标题】:Standard or custom exception in C++?C++ 中的标准或自定义异常?
【发布时间】:2011-01-20 13:29:50
【问题描述】:

对于库代码,创建并抛出自定义异常类(library::Exception)是更好的做法,还是只抛出标准异常(runtime_error、invalid_argument 等)?

【问题讨论】:

标签: c++ exception standards


【解决方案1】:

通常您应该在stdexcept 标头或其子类中抛出类的实例。究竟什么类有意义取决于具体问题。我认为抛出“类别类”std::logic_errorstd::runtime_error 的实例很少有用,因为它们没有内在含义;它们用于区分可能发生异常的两种主要情况:

  • 如果函数被调用,std::logic_error 的子类应该被抛出,但并非所有先决条件都得到满足。例外是调用者的错误,因为它未能提供必要的先决条件。对于此类别,您通常必须在抛出和未定义行为之间进行选择;这是健壮性和效率之间的权衡(例如std::vector::at()std::vector::operator[]。这些异常通常无法处理;它们是程序中的错误的结果。

  • std::runtime_error 的子类如果满足所有先决条件但函数不能满足后置条件或由于程序无法控制的原因破坏不变量(例如,文件不存在,网络连接丢失,或没有足够的可用内存)。通常应该处理这些异常。

我认为可用的 logic 错误类(例如invalid_argument)通常已经足够好,因为如果它们被引发,代码通常必须被修复,并且没有理由进行精心处理例行公事。另一方面,标准库中的runtime 错误类本质上不太灵活,主要涵盖标准库本身必须抛出异常的区域。对于您的应用程序,您应该几乎总是从这些运行时错误类继承。例如,如果构造函数分配资源失败,管理操作系统资源 X 的类应该抛出一个继承自 std::runtime_errorX_creation_error

多重虚拟继承通常对异常类很有用。您可以从std::runtime_error 或其他stdexcept 类、从某些特定于您的库的“标记类”以及从boost::exception 继承,以获得Boost.Exception library 的额外好处。强烈推荐 Boost.Exception 教程,尤其是 Exception types as simple semantic tagsUsing virtual inheritance in exception types

【讨论】:

    【解决方案2】:

    通常最好专门化(继承)一个标准异常并抛出它。

    这样就可以通过捕获std::exception 将其捕获为通用异常,但如果您需要更专业的代码,您也可以专门捕获您的自定义异常类型。

    另请参阅C++Faq,了解扔什么。

    【讨论】:

    • 基本上没有比这更好的答案了。创建您自己的继承自 std::runtime_error 的自定义异常类(它已经继承自 std::exception)。这样,您的客户可以选择捕获您的特定异常,或者只捕获 std::exception 或 std::runtime_error。
    • +1 这还有一个额外的好处,就是让您有机会在抛出的异常中添加附件。您可以包含更多信息,例如生成异常的代码的文件名和行号。请参阅此示例:stackoverflow.com/questions/4595350/…
    • 我会说这取决于情况。在我维护的代码库中,您想要在每个异常的基础上捕获的错误非常少。要么你有一个非常具体的异常要处理,要么让它们冒泡到用户界面。因此,在许多情况下,不需要非常结构化的异常层次结构,标准类(可能增加了一些自定义类)可以干净地完成工作。当参数无效时抛出std::invalid_argument,一般抛出logic_errorruntime_error,并为bad_my_custom_dynamic_cast之类的东西创建自定义异常。
    • @Alexandre C.:如果您需要一个完全具有std::logical_errorstd::invalid_argument 语义的异常,那很好:您可以使用那个。但是,如果您的语义(甚至稍微)不同,我认为最好使用新的异常类型。如果需要捕获异常的代码捕获了一个通用异常(std:: 一个),这不会有任何区别,但如果代码可能需要针对您的确切异常进行专门化,则会有很大的不同。跨度>
    • 我只是理解自定义异常类允许用户过滤库抛出的所有异常,标准异常允许用户区分异常类型(例如无效参数)。但我不喜欢创建更多自定义异常类来允许两者的想法。
    【解决方案3】:

    恕我直言自定义异常。您图书馆的客户会对此表示赞赏。他会知道究竟是什么引发了异常。

    【讨论】:

      【解决方案4】:

      根据经验,您需要的异常类很少。

      在我的大部分代码中(主要是数字——如果你这样做,例如 IO,情况就不同了),我抛出标准异常(runtime_errorinvalid_argument,...),因为它们往往表示某些东西无法轻易从其中恢复(可能invalid_argument 除外),并且可能不会被用户代码捕获(可能在顶层向用户抛出消息框除外)。

      如果存在一些旨在被典型用户代码捕获的异常,例如。 bad_custom_castbad_market_data_identifier,而不是冒泡到 main(如数字例程中的失败,或 bad_alloc),我创建了一个自定义类。但这实际上很少见。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-09
        • 1970-01-01
        • 1970-01-01
        • 2013-10-13
        • 2023-03-25
        • 1970-01-01
        • 2019-07-10
        • 1970-01-01
        相关资源
        最近更新 更多