如何在C++中捕获“任何”异常?

6

据我理解,在C++中所有的异常最终都是扩展自exception类。在Java世界中,无论Exception的类型是什么,捕获Exception e都可以起作用。那么在C++中如何做到这一点呢?

为什么在这段代码中没有捕获到异常呢?

try{        
    int z = 34/0;
    cout << "This line should not appear" << endl;
} catch (exception e) {
    cout << "An error has occurred: " << e.what();  // Not executed
}

此外,在C ++中,如何找出哪些操作会导致什么异常?

https://dev59.com/ynRC5IYBdhLWcg3wYP6h - Mysticial
顺便提一下,当出现异常时——即使是从std::exception派生的异常——这仍然不能正常工作。您需要捕获一个引用,以便多态发生: 您的代码捕获了一个被截断为基类exception副本 - user1084944
4个回答

6
在这段代码中为什么异常被捕获不到呢?
由于整数被0除不是标准的C++异常,因此在这种情况下不会抛出任何异常,而是得到一个未定义的行为。某些特定的编译器可能会将此场景映射到特定的异常,并且您需要检查编译器文档以找到相同的内容。然而,使用这样的功能将是非可移植的,并且您的代码将受限于您特定的编译器。在这种情况下,您可以做的最好的事情是自己检查错误条件(除数等于零),并明确地抛出异常。
此外,在C++中,如何找出哪些操作导致了哪些异常呢?可以使用std::exception类提供的方法std::exception::what()来实现。

1
顺便问一下,捕获exception会捕获其他异常吗? - James Leonard
3
只有这些异常是 std::exception 的子类才能被捕获。如果要捕获 所有异常,只需使用 catch(...)。请参见这里 - chrisaycock
4
你在学习时应该把Java当作参考的对象而非必须跟随的标准。这两种语言是不同的,所以在学习时需要假装不知道Java;任何相似之处仅仅是巧合,甚至可能只是表面上看起来相似。 - GManNickG
3
请注意,使用一个万能的 catch(...) 通常是不好的做法。它只是隐藏了程序中的错误,你应该避免使用它。相反,你应该只捕获特定的异常并修复可能导致意外异常抛出的错误。 - Alok Save
@asgs 说得对。不过,我以为这个话题仍然是“捕获_任何_异常”。这并不意味着被抛出的“对象”实际上在其名称中带有“异常”这个词。 - Christian.K
显示剩余5条评论

2
除以0会导致大多数CPU执行某种升级程序,可能称为异常、信号、中断、陷阱或该CPU制造商的其他术语。即使使用“异常”这个术语,这些术语也与C++语言异常没有任何直接关系。
在C++中,由于反复测试除以零通常在CPU周期和目标代码大小上昂贵,所以不需要编译器生成内置类型的任何检查。实践中,通常足以相信程序员将编写避免除以零的代码,在有用的分部分插入显式检查;分解此类检查以避免冗余。
如果程序员想要一致的保证检查,可以创建一个用户定义类型(具有自定义重载运算符的类),该类型可以用作内置数值类型的替代品,但需要花费时间来检查除以零(或下溢、上溢或其他开发人员关心的问题)并根据程序员的喜好做出反应。我了解到,像JAVA和C#这样的语言缺乏运算符重载,这意味着它们无法痛lessly以这种方式替换内置类型,需要侵入性代码更改来明确调用函数,而不是使用直观的数学运算符。
无论如何,由于C ++标准本身并未为除以零情况指定某些行为,实现可以自由选择提供一些可能有用的行为。这可能包括以某种方式生成实际的C++语言异常,但在实践中它很可能过于昂贵,以至于无法证明CPU周期和代码大小的合理性。也许JAVA本来就太慢和臃肿了,像这样的额外检查既不在这里也不在那里...?;-)
假设您使用x86系列CPU,除以0通知的术语是“中断”。但是,如果该计算机运行UNIX或Linux,该除法会在操作系统级别引发“信号”,并且您可以设置信号处理程序以获取有关问题的通知。

1

你写道:

我理解在 C++ 中所有的异常最终都是扩展自 exception

这是错误的。C++ 异常可以是任何类型。在 C++98 中,它必须是可复制的,但很可能(也很可能)这个限制已经在 C++11 中被取消了。

在 Java 世界中,无论 Exception 的类型是什么,捕获 Exception e 都可以起作用。在 C++ 中如何实现?

通过一个 catch-all 子句,

    catch( ... )

主要问题是如果你想要关于异常的任何信息,那么在 C++98 中你必须重新抛出,这不是一种特别有效的方式。截至 2012 年,你的工具链可能还不支持 C++11 的异常处理设施。

为什么在这段代码中异常没有被捕获?

因为没有 C++ 异常。通常编译器会拒绝编译常量表达式 34/0。我想不出除了 g++ 之外的任何编译器都会编译它:你真的编译过那段代码吗?

无论如何,如果有人成功编译了那段代码,从标准的C++角度来看,它只会导致未定义行为,任何事情或什么都可能发生。如果你很幸运,你可能会得到一个signal,但没有什么是保证的。然而,可以使用特定于平台的功能来捕获这些事件。

0

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