5

据我了解,c++ 中的所有异常最终都会扩展exception. Exception e在 Java 世界中,无论异常类型如何,捕获都会起作用。这是如何在 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++ 中,如何找出哪些操作导致了哪些异常?

4

4 回答 4

6

为什么在这个片段中没有捕获异常?

整数除以0不是标准的 c++ 异常。所以在这种情况下不会抛出异常,你得到的是一个普通的Undefined Behavior

一些特定的编译器可能会将此场景映射到特定的异常,您必须检查编译器文档才能找到相同的异常。但是,使用此类功能将是不可移植的,并且您的代码将仅限于您的特定编译器。

在这种情况下,您可以做的最好的事情是自己检查错误条件(除数等于 0)并显式抛出异常。

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

该类为此std::exception提供了一个std::exception::what()专门的方法。

于 2012-08-29T03:47:26.770 回答
2

除以 0 会导致大多数 CPU 遵循某种升级过程,在该 CPU 制造商的行话中,这可能被称为异常、信号、中断、陷阱或其他任何内容。这些都没有——即使也使用了“异常”这个术语——与 C++ 语言异常有任何直接关系。

在 C++ 中,由于重复测试除以零的 CPU 周期和目标代码大小通常很昂贵,因此编译器为内置类型生成的代码不需要进行任何此类检查。在实践中,通常相信程序员会编写代码以避免被零除,在有用的除法子集中插入显式检查就足够了;考虑此类检查以避免冗余。

如果程序员想要一致的保证检查,他们可以创建一个用户定义类型(一个具有自定义重载运算符的类),它可以用来代替内置的数字类型,但需要花时间检查除以零(或下溢,溢出或开发人员所关心的任何其他问题)并根据程序员的喜好做出反应。我收集到像 JAVA 和 C# 这样的语言缺乏运算符重载,我想这意味着它们不能以这种方式轻松替换内置类型,需要更改侵入性代码来显式调用函数,而不是使用直观的数学运算符。

无论如何,由于 C++ 标准本身并没有为被零除的情况指定某些行为,因此实现可以自由地提供一些可能有用的行为(如果它选择的话)。可以想象,这可能包括以某种方式生成一个实际的 C++ 语言异常,但实际上它可能在 CPU 周期和代码大小方面过于昂贵,无法证明是合理的。也许 JAVA 实在是太慢太臃肿以至于像这样的一点额外检查既不存在也不存在......?;-)

假设您使用的是 x86 系列 CPU,除以 0 通知的术语是“中断”。但是,如果该机器运行的是 UNIX 或 Linux,则除法会在操作系统级别产生一个“信号”,您可以设置一个信号处理程序来获取问题通知。

于 2012-08-29T04:32:38.813 回答
1

你写

据我了解,C++ 中的所有异常最终都会扩展exception

那是错误的。C++ 异常几乎可以是任何类型。对于 C++98,它必须是可复制的,但可能(并且很可能)C++11 已经取消了该限制。

在 Java 世界中,无论异常类型如何,捕获异常 e 都会起作用。这是如何在 C++ 中完成的?

通过一个包罗万象的条款,

    catch( ... )

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

为什么在这个片段中没有捕获异常?

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

无论如何,如果有人设法编译该代码,那么从标准 C++ 的角度来看,它只会导致Undefined Behavior,任何事情都不会发生。如果你很幸运,你会得到一个signal,但没有任何保证。但是,可以使用特定于平台的功能来捕获此类事件。

于 2012-08-29T04:55:56.527 回答
0

在 C++ 中除以零不会引发异常。例如,请参见此处此处此处

于 2012-08-29T03:47:45.743 回答