【问题标题】:C++ Exception HandlingC++ 异常处理
【发布时间】:2012-06-11 03:29:10
【问题描述】:

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

#include<iostream>

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

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

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

【问题讨论】:

    标签: c++ exception exception-handling error-handling runtime-error


    【解决方案1】:

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

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

    你能做的最好的就是自己检查错误条件(除数等于0),并在这种情况下明确抛出异常。

    编辑:回答评论

    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:更新了答案。您必须捕获异常并决定如何处理它。
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 好的,谢谢!我只是感到困惑,因为其他语言会引发异常,但这是有道理的:)
    【解决方案3】:

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

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

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


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

    【讨论】:

    • 谢谢,这是有道理的。所以另一个问题。如果我不使用std::cout,而是使用std::cerr,这会引发异常,还是只打印到错误流?如果我创建自己的异常(比如说 foo)并且在我的代码中我说 throw foo,我的程序会立即被杀死并且 foo.what() 会被打印出来吗?还是我必须明确告诉 C++ 这样做?
    • @user1413793:如果您写信给std::cerr,它只会打印到错误流。您可以通过命令行上的重定向将输出流和错误流发送到不同的地方(&gt; vs 2&gt;)。如果您throw 一个异常,并且您没有在任何地方捕获它,程序将立即终止并打印一条错误消息。 (更准确地说,将调用一个名为std::terminate 的函数,其默认行为是终止程序并打印异常消息。您可以通过调用std::set_terminate 来覆盖该行为。如果您有兴趣,请查看这些。)
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2011-04-27
      • 2011-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      • 1970-01-01
      相关资源
      最近更新 更多