6

所以我正在编写一些代码,我注意到除了语法、类型和其他编译时错误之外,C++ 不会抛出任何其他异常。所以我决定用一个非常简单的程序来测试一下:

#include<iostream>

int main() {
    std::count<<5/0<<std::endl;
return 1
}

当我使用 g++ 编译它时,g++ 给了我一个警告,说我正在除以 0。但它仍然编译了代码。然后当我运行它时,它打印了一些非常大的任意数字。当我想知道的是,C++ 如何处理异常?整数除以 0 应该是一个非常简单的例子,说明何时应该抛出异常并且程序应该终止。

我是否必须将整个程序封装在一个巨大的 try 块中,然后捕获某些异常?我知道在 Python 中,当抛出异常时,程序将立即终止并打印出错误。C++ 做什么?甚至是否存在停止执行并终止程序的运行时异常?

4

4 回答 4

12

存在运行时异常,但并非所有“错误”都会导致引发运行时异常。例如,越界访问数组或取消引用空指针只是“未定义的行为”——这意味着任何事情都可能发生。除以零也属于“未定义”类别。

导致“未定义行为”而不是异常的某些操作的基本原理是效率。假设越界数组访问需要抛出异常。然后编译器必须为每个数组访问生成代码,以检查它是否超出范围,如果是,则抛出异常。这是很多检查,其中大部分是不必要的。相反,编译器所做的只是为元素访问生成指令,假设它在界限内。如果它恰好超出范围,那么无论发生什么(例如分段错误)都会发生。如果您想要执行检查,您总是可以显式地对其进行编码。

这使得 C++ 比总是进行检查的语言(例如 Java 或 python)更强大,因为您可以选择何时需要检查,何时不需要。(另一方面,它使 C++ 的安全性低于 Java 或 python。这是一种权衡)。


至于抛出异常但没有在任何地方捕获时会发生什么,通常编译器实现会打印一条包含异常的错误消息what()。在您的示例中,这不适用,因为没有引发运行时异常。

于 2012-06-07T04:35:44.323 回答
3

是的,存在运行时异常。一个例子是out_of_range,它由vector::at.

但是,除以零是未定义的(C++0x §5.6/4):

如果 / 或 % 的第二个操作数为零,则行为未定义。

所以它可能无法编译、抛出一个虚构的异常、打印“一些非常大的任意数字”或段错误。

于 2012-06-07T04:33:13.593 回答
2

C++ 只抛出在 C++ 标准中明确定义的标准异常。(是的,它包括一些运行时异常

整数除以零不是标准的 C++ 异常(从技术上讲,它是未定义的行为)。所以不会抛出隐式异常。特定的编译器可能会将运行时错误映射到某种异常(您需要为此检查编译器文档,一些编译器将除以零映射到某个异常),如果是这样,您可以捕获该特定异常。但是,请注意,这不是可移植行为,并且不适用于所有编译器。

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

编辑:回答评论

class A
{
    public:
         void f()
         {
             int x;
             //For illustration only
             int a = 0;
             if(a == 0)
                  throw std::runtime_error( "Divide by zero Exception"); 
             x=1/a;
         }

         A()
         {
              try
              {
                   f();
              }
              catch(const std::runtime_error& e)
              {
                   cout << "Exception caught\n";
                   cout << e.what(); 
              }
         }
 };     
于 2012-06-07T04:36:32.377 回答
0

Visual C++ 正确地将此标记为除以零错误。因此,如果它不编译,那么就没有运行它的问题。

于 2012-06-07T04:31:31.340 回答