我一直相信,如果一个方法可以抛出异常,那么不使用有意义的try块来保护这个调用就是鲁莽的。

我刚刚发布了‘你应该总是包装调用,可以抛出try, catch块。,结果被告知这是一个“非常糟糕的建议”——我想知道为什么。


当前回答

我想在这个讨论中补充一点,自从c++ 11以来,它确实很有意义,只要每个catch块重新抛出异常,直到它可以/应该被处理为止。通过这种方式可以生成反向跟踪。因此,我认为前面的观点在某种程度上已经过时了。

使用std::nested_exception和std::throw_with_nested

在这里和这里的StackOverflow描述了如何实现这一点。

由于可以对任何派生异常类执行此操作,因此可以向这样的回溯添加大量信息! 你也可以看看我在GitHub上的MWE,在那里回溯看起来是这样的:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

其他回答

As Mitch and others stated, you shouldn't catch an exception that you do not plan on handling in some way. You should consider how the application is going to systematically handle exceptions when you are designing it. This usually leads to having layers of error handling based on the abstractions - for example, you handle all SQL-related errors in your data access code so that the part of the application that is interacting with domain objects is not exposed to the fact that there is a DB under the hood somewhere.

除了“在任何地方捕获所有东西”的味道之外,还有一些相关的代码味道是您一定要避免的。

"catch, log, rethrow": if you want scoped based logging, then write a class that emits a log statement in its destructor when the stack is unrolling due to an exception (ala std::uncaught_exception()). All that you need to do is declare a logging instance in the scope that you are interested in and, voila, you have logging and no unnecessary try/catch logic. "catch, throw translated": this usually points to an abstraction problem. Unless you are implementing a federated solution where you are translating several specific exceptions into one more generic one, you probably have an unnecessary layer of abstraction... and don't say that "I might need it tomorrow". "catch, cleanup, rethrow": this is one of my pet-peeves. If you see a lot of this, then you should apply Resource Acquisition is Initialization techniques and place the cleanup portion in the destructor of a janitor object instance.

我认为充斥着try/catch块的代码是代码评审和重构的好目标。它表明要么异常处理没有被很好地理解,要么代码已经变成了无用的,急需重构。

我的计算机科学教授曾经给我的建议是:“只有在使用标准方法无法处理错误时,才使用Try and Catch块。”

作为一个例子,他告诉我们,如果一个程序在一个地方遇到了一些严重的问题,而不可能做这样的事情:

int f()
{
    // Do stuff

    if (condition == false)
        return -1;
    return 0;
}

int condition = f();

if (f != 0)
{
    // handle error
}

然后你应该使用try, catch块。虽然您可以使用异常来处理这个问题,但通常不建议这样做,因为异常会消耗大量性能。

正如在其他回答中所述,只有在可以对异常进行某种合理的错误处理时才应该捕获异常。

例如,在生成您的问题的问题中,提问者询问忽略从整数到字符串的lexical_cast异常是否安全。这样的阵容永远不会失败。如果它失败了,说明程序中出现了严重的错误。在这种情况下,你能做些什么来恢复呢?最好的方法可能是让程序死亡,因为它处于不可信任的状态。因此,不处理异常可能是最安全的做法。

Herb Sutter在这里写过这个问题。绝对值得一读。 摘要:

"Writing exception-safe code is fundamentally about writing 'try' and 'catch' in the correct places." Discuss. Put bluntly, that statement reflects a fundamental misunderstanding of exception safety. Exceptions are just another form of error reporting, and we certainly know that writing error-safe code is not just about where to check return codes and handle error conditions. Actually, it turns out that exception safety is rarely about writing 'try' and 'catch' -- and the more rarely the better. Also, never forget that exception safety affects a piece of code's design; it is never just an afterthought that can be retrofitted with a few extra catch statements as if for seasoning.

我同意你的问题的基本方向,即在最低级别处理尽可能多的异常。

一些现有的回答是这样的:“您不需要处理异常。别人会在上面做的。”根据我的经验,这是一个不考虑当前开发的代码段异常处理的糟糕借口,让异常处理其他人或以后的问题。

在分布式开发中,这个问题会急剧增加,在分布式开发中,您可能需要调用由同事实现的方法。然后,您必须检查嵌套的方法调用链,以找出他/她为什么向您抛出一些异常,这在嵌套最深的方法中可以更容易地处理。