省略号、C++中的try-catch语句

3

一个省略号try-catch能否用于捕获所有可能导致崩溃的错误?是否存在任何异常情况?

try
{
//some operation
}
catch(...)
{
}

2
所有的答案都存在一个小的不精确性:在C++中,你可以抛出任何东西,而不仅仅是异常,因此请将答案阅读为使用已被抛出的任何东西,而不是所有异常 - David Rodríguez - dribeas
6
如果您的意图是添加一个通用的处理程序来防止程序崩溃,请不要这样做。相反,应该修复代码中的错误。 - John Dibling
@David:但无论你抛出什么,即使是int(1),都会变成异常。 - Martin York
4个回答

13

不,它只会捕获C++异常,而不能捕获诸如段错误、SIGINT等其他东西。

你需要了解C++异常和“C风格”的信号(例如SIGINT)之间的区别并加以理解。


5
根据编译器及其设置,它可能会在Windows上捕获SEH异常(包括访问冲突等问题)。 - Cat Plus Plus

1

这是全捕获异常处理程序
它可以捕获从try块抛出的所有C++异常。它不会捕获导致程序崩溃的段错误和其他信号。

在使用它时,您需要将此处理程序放置在所有其他特定catch处理程序的末尾,否则所有异常都将被该处理程序捕获。

使用全捕获异常处理程序是一个不好的主意,因为它只掩盖了问题并且通过捕获所有(甚至未经识别的)异常来隐藏了程序的无能。如果您遇到这种情况,最好让程序崩溃,并创建一个可以稍后分析并解决问题根源的崩溃转储。


这是一个很好的记录想法。只需确保继续使用throw;进行抛出。 - Mooing Duck
@MooingDuck: 不是真的。你会失去类型信息,你只能记录“哎呀,异常,抱歉”。最好在顶级处理程序中捕获std::exception - Cat Plus Plus
1
我认为说使用它是个坏主意基本上是错误的。我会把一个全能处理程序比作军用飞机上的弹射座椅。是的,你宁愿永远不要使用它,但当事情变得足够糟糕时,使用它仍然比在火焰中坠落要好。 - Jerry Coffin
@JerryCoffin:没有一个答案实际上指出使用它并不是一个好的做法,我尝试过了,也许我的话没有表达我想要的东西,但无论如何,我都试图传达正确的事情。我不知道用户是凭借头脑还是群体心态投票,但我因为说了一件正确但不太受欢迎的事情而得到了3个反对票。 - Alok Save
1
@Vlad:不完全是这样。catch(...)子句仅针对C++异常调用。要调用它,堆栈必须足够一致,以便追溯到找到catch处理程序。在此过程中,堆栈展开将(尝试)销毁本地内容。这通常涉及一些delete操作,因此如果堆栈非常损坏,则可能在到达处理程序之前退出到操作系统。在该处理程序中,系统极其损坏的机会实际上相当遥远。您链接的文章谈到了SetUnhandledExceptionFilter——这是完全不同的情况。 - Jerry Coffin
显示剩余11条评论

1
如果try/catch块中的代码出现了错误,程序无论如何都处于不可恢复的状态。你不应该试图防止崩溃,程序能做的最好的事情就是让进程崩溃。
"异常"在于你的代码只捕获异常而不是错误。即使代码是异常安全的(如果你正在尝试通过try/catch块来解决它的错误,这可能并不是这样),任何其他内部错误都可能使程序处于不可恢复的状态。没有办法保护程序免受这种问题的影响。

附加:查看《The Old New Thing》中的本文获取一些见解。


虽然这仍然对于记录很有用。只需确保以 throw; 语句结束 catch 块以继续抛出异常。 - Mooing Duck
@MooingDuck:我不会在万能块中进行任何日志记录。您永远不知道程序状态有多么严重的损坏,最好的方法是尽可能少地处理,以防止例如破坏用户数据。 - Vlad
@MooingDuck:是的 :-) 看看我引用的文章。 - Vlad
好文章。我曾经争论过尝试使用类型化的代码不会有害,直到我意识到在失败状态下记录到std::cerr可能会覆盖RIA流或进程间内存的缓冲区,然后在堆栈展开期间刷新。所以你是对的。最小化损害。不要使用catch (...) - Mooing Duck
@MooingDuck:确实,在Visual C++中,catch(...)可以捕获SEs,因此程序可能处于非常糟糕的状态。 - Vlad

0

它可以捕获所有被抛出的东西,不仅限于异常。但它无法处理像Windows调试断言、系统信号、段错误等问题。

TEST(throw_int) {
    try {
        throw -1;
    } catch (std::exception &e) {
        std::cerr << "caught " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "caught ..." << std::endl;
    }
}

虽然抛出整数并不是推荐的做法。最好抛出从std::exception继承而来的东西。

你可能期望在记录失败的最后一招中看到这样的东西。有些应用程序不需要非常健壮。如果您经过艰苦的努力使它们比混合在一起的垃圾更好,那么内部工具可能会比它们的价值更高。

int main(int argc, char ** argv) {
    try {
        // ...
    } catch (std::exception &e) {
        std::cerr << "error occured: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

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