C++异常处理

6

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

#include<iostream>

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

当我使用g++编译它时,g++警告我正在除以0。但它仍然编译了代码。然后当我运行它时,它打印出一个非常大的任意数字。我的问题是,C++是如何处理异常的?整数除以0应该是抛出异常并终止程序的一个非常微不足道的例子。我是否需要在try块中包含整个程序,然后捕获某些异常?我知道在Python中,当抛出异常时,程序会立即终止并打印出错误。C++会做什么?甚至有停止执行和杀死程序的运行时异常吗?
4个回答

11

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

某些操作结果出现“未定义行为”而不是异常的原因在于效率。假设访问越界的数组需要抛出异常。那么编译器必须为每个数组访问生成代码来检查是否越界,如果越界,则抛出异常。这是很多检查,其中大部分都是不必要的。相反,编译器所做的就是仅生成元素访问的指令,假设它在边界内。如果它恰好超出了边界,那么无论发生什么(比如段错误)都会发生。如果您希望执行检查,可以始终明确编写代码。

这使得 C++ 比那些总是进行检查的语言(例如 Java 或 Python)更加强大,因为您可以选择何时进行检查,何时不进行检查。(另一方面,这使得 C++ 比 Java 或 Python 更不安全。这是一个权衡)


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


谢谢,这很有道理。那么另一个问题是,如果我使用std::cerr而不是std::cout,会抛出异常还是只是打印到错误流中?如果我创建自己的异常(比如说foo),并在我的代码中使用throw foo,那么我的程序会立即被终止并打印出foo.what()吗?还是我必须明确告诉C++去这样做? - user1413793
如果你写入 std::cerr,它将简单地打印到错误流。你可以通过命令行重定向将输出流和错误流发送到不同的位置(> vs 2>)。如果你throw一个异常,并且你没有在任何地方捕获它,程序将立即终止并打印一个错误消息。(更准确地说,将调用一个名为 std::terminate 的函数,其默认行为是终止程序并打印异常的消息。如果你感兴趣,可以通过调用 std::set_terminate 来覆盖这种行为。) - HighCommander4

3
是的,有运行时异常。一个例子是out_of_range,它由vector::at抛出。
然而,除以零是未定义的(C++0x §5.6/4):
如果除法或模运算的第二个操作数为零,则行为未定义。
因此,它可能无法编译,抛出一个虚构的异常,打印“一些非常大的任意数字”或者导致段错误。

好的,谢谢!我只是有点困惑,因为其他语言会抛出异常,但这很有道理 :) - user1413793

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(); 
              }
         }
 };     

抛出异常会导致程序终止并打印出异常吗?还是我必须捕获异常并明确告诉C++该怎么做? - user1413793
1
@user1413793:已更新答案。您需要捕获异常并决定如何处理它。 - Alok Save

0

Visual C++ 正确地将其标记为除以零错误。因此,如果它无法编译,则无法运行。


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