std::exception和"..."之间的区别

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

问题是A能够捕获什么,而B不能。

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

--- 添加 对不起,我应该说我了解在C ++中您可以抛出任何类型,但除此之外还可以抛出什么?

我的问题是,我正在尝试查找从代码中抛出的异常,可以由A捕获但由B无法捕获。 这个异常肯定不是像“int”这样的类型。它必须是系统异常或内存违规之类的事情。 我只是想知道那可能是什么。


C++没有一个所有异常都继承的“根”异常类型,因为C++可以抛出任何东西,包括不能继承的类型,比如int。C++之所以可以抛出任何东西,是因为他们认为没有理由让异常变得不够通用。这与C++模板类似;C++模板不依赖于继承,因此比如Java或C#的泛型更加通用,而后者则依赖于继承。 - bames53
1
有些Windows SEH异常有时候可以被“…”捕获,但不能被“std :: exception”捕获。 - Mooing Duck
只有在使用疯狂的标志进行编译,并使用推荐的 /EHsc(如果可以的话),你才能正常运行 @MooingDuck。 - Mike Vine
3个回答

31

catch (...) 是所谓的“万能捕获块”,它会捕获任何 C++ 异常。

catch(std::exception& e) 仅会捕获从 std::exception 派生的异常。

这是一个将被万能捕获块捕获,但不会被第二个版本捕获的异常示例:

throw 42;
这可能对您来说有些奇怪,事实也确实如此。重要的是要意识到,任何东西都可以作为C++异常抛出——不仅限于exception或从exception派生的内容。正如@bames53在评论中提到的那样,没有像其他一些语言中那样所有异常都派生自一个根异常类型。
另外需要注意的是,捕获所有块很容易被滥用。事实上,一般的经验法则是,最好假定所有捕获所有块都是程序缺陷。当然,在编程中没有“总是”,但学习使用异常时,这是一个安全的假设起点。
捕获所有块之所以邪恶,是因为它们通常的使用方式。通常,一个天真的程序员会写一个捕获所有块,试图捕获任何编程错误,然后关键地继续让程序运行,就好像什么都没发生一样。这是一场等待爆发的灾难。程序状态现在是不确定的。某些东西出了问题。你不能安全地忽略异常并继续像一切都很好一样运行。即使你的程序继续运行,可能某个地方存在微妙的堆破坏,会损害程序的计算或输出。当堆破坏发生时,作为程序员能够期望的最好情况是立即崩溃。这样,您就可以在破坏点获得调用堆栈和转储文件,并找到并修复问题。但如果放置了捕获所有块,您就失去了此破坏发生的所有上下文。几乎不可能找到代码中真正的缺陷。
当然,捕获所有句柄有有效和有价值的用途。其中一个最常见的用途是编写全局异常处理程序,然后重新throw异常。这个全局处理程序可以启动某种故障记录,例如通过记录错误本身或生成外部程序来在失败的程序外部进行记录。通过重新抛出异常,您给代理一个处理可处理的异常的机会,同时允许无法处理的异常终止程序。
重新抛出异常很容易实现。只需像以下方式一样调用没有参数的throw即可:
catch (...)
{
  // some magic
  throw;
}
另一个需要记住的事情是,当你捕获异常时,通常最好捕获const引用,而不仅仅是引用。

需要注意的另一点是,在使用try-catch语句时,对于可能抛出异常的代码块应该尽量简短,以免降低程序性能。


如果您的代码中有多处可能抛出异常的地方,可以考虑将这些代码块分解成较小的函数,这样可以提高代码的可读性和可维护性。


在处理异常时,要根据具体情况选择使用何种处理方式,比如可以直接处理异常,也可以将异常抛给调用者处理。



5
一些旧版的VC++(甚至一些新版在特定设置下也可能如此)用catch(...)也会捕获SEH异常,这绝不是个好主意(你可能会忽略一个访问冲突或用于扩展堆栈的页保护异常)。 - Matteo Italia
@MatteoItalia:你确定吗?我很久没有处理SEH了,你可能是对的,但我不记得了。 - John Dibling
我不确定旧的默认行为,但你肯定可以仍然更改设置以启用捕获SEH异常。 - jerry
@JohnDibling:如果我没记错的话,这是在VC++ 2003(7.1)中发生的,我记得曾经被这个问题困扰过。 - Matteo Italia
请查看我对主问题的评论,关于捕获SEHs,它不再是默认设置(幸运的是已经有一段时间了),但如果您足够疯狂,可以启用它。 - Mike Vine
显示剩余2条评论

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

输出:

捕获到其他异常

1
如何处理int类型?
try {
    throw 123;
} catch (std::exception &e) {
    // this won't catch
} catch (...) {
    // this will catch
}

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