【发布时间】:2010-12-06 21:13:30
【问题描述】:
std::runtime_error 和 std::exception 有什么区别?每个的适当用途是什么?为什么它们首先不同?
【问题讨论】:
std::runtime_error 和 std::exception 有什么区别?每个的适当用途是什么?为什么它们首先不同?
【问题讨论】:
std::exception 是唯一目的是作为异常层次结构中的基类的类。它没有其他用途。换句话说,从概念上讲,它是一个抽象类(尽管它在 C++ 术语的含义中没有被定义为抽象类)。
std::runtime_error 是一个更专业的类,源自std::exception,旨在在各种运行时错误的情况下抛出。它有双重目的。它可以自己抛出,也可以作为各种更专业类型的运行时错误异常的基类,例如std::range_error、std::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 派生对象。
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::string)。现在我意识到如果我想让我的代码在 Linux (GCC) 中工作,我必须抛出 std::runtime_error。