16
A:      catch(...)  
B:      catch(std::exception& e)

问题是 A 能捕捉到什么,而 B 不能。

为什么在 C++ 中没有引入可以捕获任何东西的通用根异常

--- 补充说对不起,我应该说我理解在 C++ 中你可以抛出任何类型,如 int,但除此之外,还能抛出什么?

我的问题是我试图找出代码抛出了什么异常,它可以被A捕获但不能被B捕获。这个异常绝对不是像“int”这样的类型。它必须是系统异常或内存违规之类的事情。我只是想知道那可能是什么。

4

3 回答 3

31

catch (...)是所谓的“包罗万象”块。它将捕获任何C++ 异常。

catch(std::exception& e)将仅捕获派生自std::exception.

这是一个将由 catch-all 调用的异常示例,但不是第二个版本:

throw 42;

这对你来说可能看起来很奇怪,而且确实如此。要意识到的重要一点是,任何东西都可以作为 C++ 异常抛出——不仅仅是exceptions 或派生自exception. 正如@bames53 在评论中提到的那样,没有所有异常都源自的根异常类型,就像在其他一些语言中一样。

同样重要的是要注意,一个包罗万象的块很容易被滥用。事实上,作为一般的经验法则,最好假设所有 catch-all 块都是程序缺陷。当然,编程中没有“总是”,但是当您学习使用异常时,这是一个安全的假设。

包罗万象的方块之所以是邪恶的,是因为它们通常是如何使用的。通常,一个天真的程序员会编写一个包罗万象的程序,试图捕捉任何编程错误,然后,至关重要的是,继续让程序运行,就好像什么都没发生一样。这是一场等待发生的灾难。程序状态现在是不确定的。某事,某处出了问题。您不能安全地忽略异常并继续进行,就像一切都很好。即使您的程序确实继续运行,也可能会在某处出现细微的堆损坏,从而掺杂程序的计算或其输出。当堆损坏确实发生时,作为程序员的你所希望的最好的事情就是立即崩溃。这样,您可以在损坏点获取调用堆栈和转储文件并找到并修复问题。但是当你有一个包罗万象的地方时,你就失去了发生这种腐败的所有背景。几乎不可能在代码中找到真正的缺陷。


当然,catch all 处理程序有一些有效且有价值的用途。最常见的一种是编写一个全局异常处理程序,然后重新处理throw异常。这个全局处理程序可以启动某种故障记录,可能是通过记录错误本身,或者生成一个在失败程序之外进行记录的外部程序。通过重新抛出异常,您可以让委托人有机会处理可以处理的异常,同时允许无法处理的异常终止程序。

重新抛出异常很简单。只需throw不带参数调用,如下所示:

catch (...)
{
  // some magic
  throw;
}

要记住的另一件事是,当您确实捕获异常时,通常最好捕获const引用,而不仅仅是引用。

于 2013-07-01T15:15:05.090 回答
2

简短的回答是std::exception在其(公共)继承层次结构中没有任何东西:

#include <exception>
#include <iostream>

int main()
{
    try
    {
        throw false;
    }
    catch(std::exception& e)
    {
        std::cout << "Caught std::exception" << std::endl;
    }
    catch(...)
    {
        std::cout << "Caught something else" << std::endl;
    }

    return 0;
}

输出:

抓到别的东西
于 2013-07-01T15:19:57.240 回答
1

s怎么样int

try {
    throw 123;
} catch (std::exception &e) {
    // this won't catch
} catch (...) {
    // this will catch
}
于 2013-07-01T15:15:44.673 回答