区别:std::runtime_error 与 std::exception()

Posted

技术标签:

【中文标题】区别:std::runtime_error 与 std::exception()【英文标题】:Difference: std::runtime_error vs std::exception() 【发布时间】:2010-12-06 21:13:30 【问题描述】:

std::runtime_errorstd::exception 有什么区别?每个的适当用途是什么?为什么它们首先不同?

【问题讨论】:

【参考方案1】:

std::exception 是唯一目的是作为异常层次结构中的基类的类。它没有其他用途。换句话说,从概念上讲,它是一个抽象类(尽管它在 C++ 术语的含义中没有被定义为抽象类)。

std::runtime_error 是一个更专业的类,源自std::exception,旨在在各种运行时错误的情况下抛出。它有双重目的。它可以自己抛出,也可以作为各种更专业类型的运行时错误异常的基类,例如std::range_errorstd::overflow_error 等。您可以从std::runtime_error 定义自己的异常类,以及您可以定义自己的异常类(从std::exception 降序)。

就像std::runtime_error,标准库包含std::logic_error,也是std::exception的后代。

拥有这种层次结构的目的是让用户有机会使用 C++ 异常处理机制的全部功能。由于“catch”子句可以捕获多态异常,因此用户可以编写“catch”子句来捕获异常层次结构的特定子树中的异常类型。例如,catch (std::runtime_error& e) 将捕获来自std::runtime_error 子树的所有异常,让所有其他异常通过(并在调用堆栈中飞得更远)。

附:设计一个有用的异常类层次结构(让您在代码的每个点只捕获您感兴趣的异常类型)是一项不平凡的任务。您在标准 C++ 库中看到的是一种可能的方法,由该语言的作者提供给您。如您所见,他们决定将所有异常类型拆分为“运行时错误”和“逻辑错误”,并让您从那里继续使用自己的异常类型。当然,还有其他方法可以构建该层次结构,这可能更适合您的设计。

更新:Linux 与 Windows 的可移植性

正如 Loki Astari 和 unixman83 在他们的回答和下面的 cmets 中指出的那样,exception 类的构造函数根据 C++ 标准不接受任何参数。 Microsoft C++ 在exception 类中有一个接受参数的构造函数,但这不是标准的。 runtime_error 类在 Windows 和 Linux 两个平台上都有一个带参数 (char*) 的构造函数。为了便携,最好使用runtime_error

(请记住,仅仅因为您的项目规范表明您的代码不必在 Linux 上运行,这并不意味着它永远不必在 Linux 上运行。)

【讨论】:

谢谢。很好的答案。虽然我想知道是否需要有不同类型的异常......不过只是一个想法。 如果存在可以重新覆盖异常的可能性,那么不同类型的异常可能很有用,因为我们可以使用异常处理机制将异常定向到将尝试和处理的处理程序纠正问题。如果没有恢复的机会,那么标准例外之一就可以了。 顺便说一句:在任何地方都没有规则会强制您从std::exception 派生。当然,所有std 的东西都会抛出派生类,但绝对没有理由只抛出std::exception 派生对象。 @rubenvb 我不知道,但我认为如果只抛出从异常派生的类的对象,它将清除代码以供将来维护。示例:我喜欢找出在我的代码库中实现了哪些自定义异常,并搜索从异常派生的类。【参考方案2】:

std::exception 应被视为(注意已考虑)标准异常层次结构的抽象基础。这是因为没有传递特定消息的机制(为此,您必须派生和专门化what())。没有什么可以阻止您使用 std::exception,对于简单的应用程序,它可能就是您所需要的。

另一方面,std::runtime_error 具有接受字符串作为消息的有效构造函数。当调用what() 时,会返回一个 const char 指针,该指针指向一个 C 字符串,该字符串与传递给构造函数的字符串相同。

try

    if (badThingHappened)
    
         throw std::runtime_error("Something Bad happened here");
    

catch(std::exception const& e)

    std::cout << "Exception: " << e.what() << "\n";
 

【讨论】:

感谢马丁的回答。但是,我使用 std::exception() 的方式与上述相同。即 std::exception() 构造函数也可以采用 std::string() 或 const char*。 不符合标准。 std::exception 有一个不带参数的构造函数。使用接受 std::string 或 C-String 的版本是不可移植的。 因为微软,我习惯了扔std::exception(std::string)。现在我意识到如果我想让我的代码在 Linux (GCC) 中工作,我必须抛出 std::runtime_error

以上是关于区别:std::runtime_error 与 std::exception()的主要内容,如果未能解决你的问题,请参考以下文章

无法捕获 std::runtime_error

如何从 std::runtime_error 继承?

误解 std::runtime_error 的 what() 函数

带有“std::runtime_error”的 C++0x random_device

为什么std :: runtime_error的c'tor采用对std :: string的常量引用?

定义自己的异常类的最佳实践?