抛出 C++ 异常时应该抛什么?

25

这可能是一个有点愚蠢的问题,但在C++中,当我想抛出异常时...我应该抛出什么?

我应该抛出std::exception,还是那是标准库保留的?或者我应该抛出一个字符串或整数?或者我应该抛出任何我觉得合适的东西?


3
不要抛出字符串或整数!如果你总是抛出std::exception的子类,那么你可以在main函数中放置一个catch-all子句来处理所有未在其他地方处理的异常,并打印异常的what() - Fred Foo
5个回答

32

抛出一个继承自 std::exception 的类;如果你 #include <stdexcept>,你可以从许多现成、有用的派生类中选择。

继承自 std::exception 允许您的处理程序遵循一种可识别的风格,因为您可以始终使用 .what() 来获取文本信息。不要抛出原始类型,因为它们不携带语义信息。


10
我认为(虽然基本相同),在大多数情况下,人们应该从std::runtime_error派生他们的异常(它本身也是从std::exception派生而来)。 - Martin York

8
一般来说,人们不会直接抛出std::exception,因为它不存储任何错误信息。这样what方法就无法返回任何内容。有时我会对此感到困惑,因为MSVC提供了一个非标准扩展,即std::exception的带参数构造函数,可以接受一个字符串。
您可以从现有的异常类中选择,例如std::runtime_exception,或定义自己的异常类。这在某种程度上是主观的,但我建议将异常类的数量保持最少,因为RAII可以消除许多需要针对不同异常类型具有多个代码分支和catch块的情况。通常,结合RAII符合规范的代码,加上消息就足以优雅地从任何异常中恢复过来。
最后,我建议你抛出的所有异常都继承自std::exception,原因类似。如果可以避免,您不希望在代码中放置许多不同的catch块以处理不同的异常类型。尽量以最一般的方式解决问题。

2
抛出继承自std::exception的异常的主要例外情况是,如果您正在使用一些具有自己的异常层次结构的框架(例如MFC),则通常应从其层次结构中的适当位置派生。请注意,我并不特别试图将MFC作为清晰的异常处理(或一般设计)的例子来阐述,只是一个包含异常层次结构的框架的示例。当您使用已经定义了异常层次结构的框架时,通常最好使用它。
换句话说,与C++中的其他偏好不同,通常认为异常应该是单一的、统一的层次结构,其中仅有一个根。对于标准库,该单一根是std::exception,但其他框架有其他选择,如果他们提供了一个,您通常会希望将自己的异常适配进去。

1

和 Java 不同的是,你可以抛出任何你想要抛出的类型(int、string、MyClass 等)。但还是要听从 Kerrek 的建议。:)


0
通常情况下,正如其他人所说,你会希望抛出从std::exception派生的异常之一。
偶尔我也会抛出其他类型的异常,但只有在同一个代码块中被捕获并且该值在该上下文中有用时。

如果你在“同一块内”捕获异常,那么你可能根本不应该首先抛出异常。异常是用于处理异常情况的,但如果你可以在那里正确地处理条件,那么它听起来就像是正常程序流程的一部分。(而且不要忘记,“抛出”异常比仅检查某些本地状态要昂贵得多。) - Kerrek SB
@KerrekSB,我记不清我是在什么情况下这样做的,但我确定这是一个异常条件,不属于“正常”流程的一部分。可能也是深度嵌套的,其他方法会更丑陋。 - Mark Ransom
2
好的。确实有一些情况,异常可以使复杂的算法更清晰易懂... - Kerrek SB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接