有人在另一个问题建议使用catch(...)
通过将整个main()
与try{}catch(...){}
块一起包围来捕获所有其他未处理的 - 意外/未预见的异常。
这听起来像一个有趣的想法,可以节省大量时间调试程序,并至少留下一些发生的事情。
问题的实质是哪些信息可以恢复那种方式(除了我留下的任何调试全局),以及如何来恢复它(如何访问)并且识别所谓的任何捕获物)
此外,有什么警告与它有关。特别是:
答案 0 :(得分:10)
是的,这是一个好主意。
如果你让异常转义为main,那么在实现定义的天气之前,堆栈会在应用程序关闭之前解开。所以在我看来,你必须抓住主要的所有例外情况。
然后问题就变成了如何处理它们 一些操作系统(参见MS和SE)提供了一些额外的调试工具,因此在捕获异常之后重新抛出异常非常有用(因为无论如何堆栈现在已经解开)。
int main()
{
try
{
/// All real code
}
// I see little point in catching other exceptions at this point
// (apart from better logging maybe). If the exception could have been caught
// and fixed you should have done it before here.
catch(std::exception const& e)
{
// Log e.what() Slightly better error message than ...
throw;
}
catch(...) // Catch all exceptions. Force the stack to unwind correctly.
{
// You may want to log something it seems polite.
throw; // Re-throw the exception so OS gives you a debug opportunity.
}
}
- 它会在稍后萌芽的线程中发挥出色吗?
它应该对线程没有影响。通常,您必须手动加入任何子线程以确保它们已退出。当主要出口没有明确定义时,子线程会发生什么事情的确切细节(因此请阅读您的文档)但通常所有子线程都会立即死亡(一种令人讨厌和可怕的死亡,不涉及展开它们的堆栈)。
如果您正在讨论子线程中的异常。同样,这个定义不明确(所以请阅读您的文档)但是如果一个线程通过异常退出(即由于异常而不是返回而用于启动线程的函数退出)那么这通常会导致应用程序终止(同样的影响)如上)。因此,最好停止所有例外退出线程。
- 它不会破坏处理段错误(在其他地方作为信号捕获)
信号不受异常处理机制的影响 但是因为信号处理程序可能会在堆栈上放置一个奇怪的结构(因为它们自己的返回处理回到正常代码),所以从信号处理程序中抛出异常不是一个好主意,因为这可能会导致意外结果(并且绝对不可移植) )。
- 它不会影响其他try ... catch块不可避免地嵌套在里面,那是否有处理预期的异常?
应该对其他处理程序没有影响。
答案 1 :(得分:4)
据我所知,Win32上的catch(...)
还会收到SEH异常,而不希望执行此操作。如果你得到SEH例外,那是因为发生了非常可怕的事情(主要是访问违规),所以你不能再相信你的环境了。您可以做的几乎所有事情都可能因另一个SEH例外而失败,因此它甚至不值得尝试。此外,一些SEH例外旨在被系统捕获;更多关于此here。
所以,我的建议是对所有异常使用基本异常类(例如std::exception
),并在“catchall”中捕获该类型;你的代码不能准备好处理其他类型的异常,因为它们根据定义是未知的。
答案 2 :(得分:3)
全局try catch块对生产系统很有用,以避免向用户显示令人讨厌的消息。在开发过程中,我认为最好避免使用。
关于你的问题:
答案 3 :(得分:1)
如果您正在制作.net应用程序,可以尝试a solution I use。这捕获了所有未处理的异常。我通常只在不使用调试器时为生产代码启用代码(#ifndef DEBUG
)。
值得指出的是,kgiannakakis提到您无法在其他线程中捕获异常,但您可以在这些线程中使用相同的try-catch方案并将异常发布回主线程,您可以在其中重新抛出它们获得错误的完整堆栈跟踪。
答案 4 :(得分:0)
以及如何恢复它(如何访问 并认识到任何捕获 叫())
如果您的意思是如何恢复抛出的异常类型,您可以在回退到catch (...)
之前链接特定类型的catch块(从更具体到更一般):
try {
...
} catch (const SomeCustomException& e) {
...
} catch (const std::bad_alloc& e) {
...
} catch (const std::runtime_error& e) {
// Show some diagnosic for generic runtime errors...
} catch (const std::exception& e) {
// Show some diagnosic for any other unhandled std::exceptions...
} catch (...) {
// Fallback for unknown errors.
// Possibly rethrow or omit this if you think the OS can do something with it.
}
请注意,如果您发现自己在多个地方执行此操作并希望合并代码(可能需要多个main
函数用于单独的程序),您可以编写一个函数:
void MyExceptionHandler() {
try {
throw; // Rethrow the last exception.
} catch (const SomeCustomException& e) {
...
}
...
}
int main(int argc, char** argv) {
try {
...
} catch (...) {
MyExceptionHandler();
}
}
答案 5 :(得分:0)
catch-all不会非常有用,因为没有可以查询的类型/对象信息。但是,如果可以确保应用程序引发的所有异常都是从单个基础对象派生的,则可以使用catch块作为基本异常。但那不是一个全能的。