C++ 我应该何时以及如何使用异常处理?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4506369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When and how should I use exception handling?
提问by Umesha MS
I am reading about exception handling. I got some information about what exception handling is, but I have a few questions:
我正在阅读有关异常处理的信息。我得到了一些关于什么是异常处理的信息,但我有几个问题:
- When to throw an exception?
- Instead of throwing an exception, can we use a return value to indicate the error?
- If I protect all my functions by try-catch blocks, won't it reduce the performance?
- When to use exception handling?
- I saw a project where each and every function in that project contained a try-catch block (i.e. code inside the entire function is surrounded by try-catch block). Is this a good practice?
- What is the difference between try-catch and __try __except?
- 什么时候抛出异常?
- 我们可以使用返回值来指示错误,而不是抛出异常吗?
- 如果我通过 try-catch 块保护我的所有功能,它会不会降低性能?
- 什么时候使用异常处理?
- 我看到一个项目,该项目中的每个函数都包含一个 try-catch 块(即整个函数内的代码被 try-catch 块包围)。这是一个好习惯吗?
- try-catch 和 __try __except 有什么区别?
回答by Septagram
Here's quite comprehensive guide on exceptions that I think is a Must Read:
这是我认为必须阅读的关于异常的非常全面的指南:
Exceptions and error handling - C++ FAQor C++ FAQ lite
异常和错误处理 - C++ FAQ或C++ FAQ lite
As a general rule of thumb, throw an exception when your program can identify an externalproblem that prevents execution. If you receive data from the server and that data is invalid, throw an exception. Out of disk space? Throw an exception. Cosmic rays prevent you from querying the database? Throw an exception. But if you get some invalid data from inside your very own program - don't throw an exception. If your problem comes from your own bad code, it's better to use ASSERTs to guard against it. Exception handling is needed to identify problems that program cannot handle and tell them about the user, because user can handle them. But bugs in your program are not something the user can handle, so program crashing will tell not much less than "Value of answer_to_life_and_universe_and_everything is not 42! This should never happen!!!!11" exception.
作为一般经验法则,当您的程序可以识别外部阻止执行的问题。如果您从服务器接收数据并且该数据无效,则抛出异常。磁盘空间不足?抛出异常。宇宙射线阻止你查询数据库?抛出异常。但是如果你从你自己的程序中得到一些无效的数据——不要抛出异常。如果您的问题来自您自己的错误代码,最好使用 ASSERT 来防范它。需要异常处理来识别程序无法处理的问题并将其告知用户,因为用户可以处理它们。但是你的程序中的错误不是用户可以处理的,所以程序崩溃会告诉不少于“answer_to_life_and_universe_and_everything 的值不是 42!这不应该发生!!!!11”的异常。
Catch an exception where you can do something useful with it, like, display a message box. I prefer to catch an exception once inside a function that somehow handles user input. For example, user presses button "Annihilate all hunams", and inside annihilateAllHunamsClicked() function there's a try...catch block to say "I can't". Even though annihilation of hunamkind is a complex operation that requires calling dozens and dozens of functions, there is only one try...catch, because for a user it's an atomic operation - one button click. Exception checks in every function are redundant and ugly.
捕捉一个异常,你可以用它做一些有用的事情,比如显示一个消息框。我更喜欢在以某种方式处理用户输入的函数中捕获一次异常。例如,用户按下按钮“歼灭所有 hunams”,在 annihilateAllHunamsClicked() 函数中,有一个 try...catch 块说“我不能”。尽管 hunamkind 歼灭是一项复杂的操作,需要调用几十个函数,但只有一次 try...catch,因为对于用户来说,这是一个原子操作——单击一个按钮。每个函数中的异常检查都是多余的和丑陋的。
Also, I can't recommend enough getting familiar with RAII - that is, to make sure that all data that is initialized is destroyed automatically. And that can be achieved by initializing as much as possible on stack, and when you need to initialize something on heap, use some kind of smart pointer. Everything initialized on the stack will be destroyed automatically when an exception is thrown. If you use C-style dumb pointers, you risk memory leak when an exception is thrown, because there is noone to clean them up upon exception (sure, you can use C-style pointers as members of your class, but make sure they are taken care of in destructor).
另外,我不能推荐足够熟悉 RAII - 也就是说,确保所有初始化的数据都被自动销毁。这可以通过尽可能多地在堆栈上初始化来实现,当您需要在堆上初始化某些内容时,请使用某种智能指针。当抛出异常时,堆栈上初始化的所有内容都将自动销毁。如果你使用 C 风格的哑指针,当抛出异常时你会面临内存泄漏的风险,因为没有人在异常时清理它们(当然,你可以使用 C 风格的指针作为你的类的成员,但要确保它们是在析构函数中处理)。
回答by Yttrill
Exceptions are useful in a variety of circumstances.
异常在各种情况下都很有用。
First, there are some functions where the cost of calculating the pre-condition is so high it is better to just do the calculation and abort with an exception if it is found the pre-condition is not met. For example, you cannot invert a singular matrix, however to calculate if it is singular you calculate the determinant which is very expensive: it may have to be done inside the function anyhow, so just "have a try" at inverting the matrix and report an error if you can't by throwing an exception. This is basically an exception as negative pre-conditionusage.
首先,有些函数计算前置条件的成本如此之高,最好只进行计算并在发现前置条件不满足时异常中止。例如,您不能反转奇异矩阵,但是要计算它是否是奇异矩阵,您需要计算非常昂贵的行列式:无论如何,它可能必须在函数内部完成,因此只需“尝试”反转矩阵并报告如果您不能抛出异常,则会出现错误。这基本上是作为否定前提条件使用的例外。
Then there are other cases where your code is already complex and passing error information up the call chain is difficult. This is partly because C and C++ have broken data structure models: there are other, better ways, but C++ doesn't support them (such as using monads in Haskell). This use is basically I couldn't be bothered to do it right so I'll throw an exception: its not the right way but it's practical.
然后还有其他情况,您的代码已经很复杂,并且很难将错误信息向上传递到调用链。这部分是因为 C 和 C++ 破坏了数据结构模型:还有其他更好的方法,但 C++ 不支持它们(例如在 Haskell 中使用 monad)。这种用法基本上是我懒得做,所以我会抛出一个异常:它不是正确的方法,但它很实用。
Then there is the main use of exceptions: to report when external pre-conditions or invariants, such as sufficient resources like memory or disk space, are not available. In this case you will usually terminate the program, or a major subsection of it, and the exception is a good way of transmitting information about the problem. C++ Exceptions were designed for reporting errors which prevent the program continuing.
然后是异常的主要用途:在外部先决条件或不变量(例如内存或磁盘空间等足够资源)不可用时报告。在这种情况下,您通常会终止程序或其中的一个主要部分,而例外是传输有关问题的信息的好方法。C++ 异常设计用于报告阻止程序继续运行的错误。
The exception handling model used in most modern languages including C++ is knownto be broken. It is vastly too powerful. Theoreticians have now developed better models than the completely open "throw anything" and "maybe and maybe not catch it" model. In addition using type information to classify exceptions wasn't a very good idea.
众所周知,包括 C++ 在内的大多数现代语言中使用的异常处理模型已被破坏。它太强大了。理论家们现在已经开发出比完全开放的“扔任何东西”和“也许还是不抓住它”模型更好的模型。此外,使用类型信息对异常进行分类也不是一个好主意。
So the best thing you can do is throw exceptions sparingly, when there's an actual error, and when there's no other way to deal with itand catch exceptions as close to the throw point as possible.
因此,您可以做的最好的事情是谨慎地抛出异常,当出现实际错误时,并且没有其他方法来处理它并尽可能接近抛出点时捕获异常。
回答by James K. Lowden
If your problem comes from your own bad code, it's better to use ASSERTs to guard against it. Exception handling is needed to identify problems that program cannot handle and tell them about the user, because user can handle them. But bugs in your program are not something the user can handle, so program crashing will tell not much
如果您的问题来自您自己的错误代码,最好使用 ASSERT 来防范它。需要异常处理来识别程序无法处理的问题并将其告知用户,因为用户可以处理它们。但是你的程序中的错误不是用户可以处理的,所以程序崩溃不会说明什么
I disagree with this aspect of the accepted answer. An assert is not hands-down better than throwing an exception. If exceptions were suitable only for run-time errors (or "external problems") , what is std::logic_error
for?
我不同意已接受答案的这一方面。断言并不比抛出异常更好。如果异常只适用于运行时错误(或“外部问题”),那是std::logic_error
为了什么?
A logic error is almost by definition the kind of condition that prevents a program from continuing. If the program is a logical construct, and a condition occurs outside the domain of that logic, how can it continue? Gather ye inputs while ye may, and throw an exception!
根据定义,逻辑错误几乎是一种阻止程序继续运行的条件。如果程序是一个逻辑结构,并且一个条件发生在该逻辑域之外,它如何继续?尽可能收集输入,并抛出异常!
It's not like there's not prior art. std::vector
, to name but one, throws a logic error exception, namely std::out_of_range
. If you use the standard library and don't have a top-level handler to catch standard exceptions -- if only to call what() and exit(3) -- then your programs are subject to abrupt silent, termination.
这不像没有现有技术。 std::vector
,举个例子,抛出一个逻辑错误异常,即std::out_of_range
。如果您使用标准库并且没有顶级处理程序来捕获标准异常——如果只是调用what() 和exit(3)——那么您的程序将受到突然的静默、终止。
An assert macro is a much weaker guard. There is no recovery. Unless, that is, you're not running a debug build, in which case there's no execution. The assert macro belongs to an era when computation was 6 orders of magnitude slower than today. If you're going to the trouble to test for logic errors, but not to use that test when it counts, in production, you'd better have a lot of confidence in your code!
assert 宏是一个弱得多的保护。没有恢复。除非,也就是说,您没有运行调试版本,在这种情况下没有 execution。assert 宏属于计算比今天慢 6 个数量级的时代。如果您要麻烦地测试逻辑错误,但在重要时不使用该测试,那么在生产中,您最好对自己的代码充满信心!
The standard library provides for logic error exceptions, and employs them. They are there for a reason: because logic errors occur, and are exceptional. Just because C features assertions is no reason to rely on such a primitive (and, arguably, useless) mechanism, when an exception handles the job so much better.
标准库提供逻辑错误异常,并使用它们。它们存在是有原因的:因为会发生逻辑错误,而且是异常的。仅仅因为 C 具有断言功能,就没有理由依赖这种原始(并且可以说是无用的)机制,当异常处理工作时要好得多。
回答by Sushan M
Best read for this
最好读这个
Exception handling has been talked about a lot over the last decade and a half. However, despite a general consensus on how to properly handle exceptions, a divide on usage continues to exist. Improper exception handling is easy to spot, easy to avoid, and is a simple code (and developer) quality metric. I know absolute rules come off as close minded or exaggerated, but as a general rule you shouldn't be using try/catch
在过去的十五年里,异常处理被讨论了很多。然而,尽管就如何正确处理异常达成了普遍共识,但在使用上的分歧仍然存在。不正确的异常处理很容易被发现,也很容易避免,并且是一个简单的代码(和开发人员)质量指标。我知道绝对规则会显得过于封闭或夸大,但作为一般规则,您不应该使用 try/catch
http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/
http://codebetter.com/karlsegin/2010/01/25/don-t-use-try-catch/
回答by user550830
1.An exception check is included in the code when there is a possibility of getting an exception as a result or somewhere in between the problem.
1.当有可能作为结果或介于问题之间的某个地方时,代码中包含异常检查。
2.Use try-catch block with only those cases where it is required. Usage of each try-catch block add to an extra condition check that certainly reduces the optimization of the code.
2.仅在需要的情况下使用 try-catch 块。每个 try-catch 块的使用都会增加额外的条件检查,这肯定会减少代码的优化。
3.I think _try_except is a valid variable name....
3.我认为 _try_except 是一个有效的变量名....
回答by pinichi
The basical difference is:
基本的区别是:
- one make error handling for you.
an one is you do your own.
For instance, you have an expression could make
0 divide error
. Using try catch1.
will help you when error occurred. Or you need anif a==0 then..
in2.
If you dont try catch the exception I dont think its faster, its just simply bypass, if
error
occurred it will bethrew
to an outer handler.
- 一个为你做错误处理。
一个是你自己做。
例如,您有一个表达式 can make
0 divide error
。使用 try catch1.
会在发生错误时为您提供帮助。或者你需要一个if a==0 then..
输入2.
如果您不尝试捕获异常,我认为
error
它不会更快,它只是简单地绕过,如果发生,它将threw
转到外部处理程序。
Handing yourself mean the problem not go further then have advantage in speed in many case, but not always.
自己动手意味着问题不会更进一步,然后在许多情况下在速度上具有优势,但并非总是如此。
Suggest:Just handling yourself when it simple and in logically case.
建议:只在简单且符合逻辑的情况下处理自己。
回答by speedplane
Many C/C++ purists discourage exceptions altogether. The main criticisms are:
许多 C/C++ 纯粹主义者完全不鼓励异常。主要的批评是:
- It's slow - Of course it isn't really "slow". However, compared to pure c/c++, there is quite a bit of overhead.
- It introduces bugs - If you don't handle exceptions properly, you can miss the clean-up code in the function that throws the exception.
- 它很慢——当然,它并不是真的“慢”。然而,与纯 c/c++ 相比,有相当多的开销。
- 它引入了错误 - 如果您没有正确处理异常,您可能会错过抛出异常的函数中的清理代码。
Instead, check the return value / error code every time you call a function.
相反,每次调用函数时都要检查返回值/错误代码。