纠正 C++ 中的异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2718779/
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
Correct Exceptions in C++
提问by Dr.Ackula
I am just learning how to handle errors in my C++ code. I wrote this example that looks for a text file called some file, and if its not found will throw an exception.
我只是在学习如何处理 C++ 代码中的错误。我写了这个例子来查找一个名为 some file 的文本文件,如果找不到它会抛出异常。
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int array[90];
try
{
ifstream file;
file.open("somefile.txt");
if(!file.good())
throw 56;
}
catch(int e)
{
cout<<"Error number "<<e<<endl;
}
return 0;
}
Now I have two questions. First I would like to know if I am using Exceptions correctly. Second, (assuming the first is true) what is the benefit to using them vs an If else statement?
现在我有两个问题。首先,我想知道我是否正确使用了异常。其次,(假设第一个是真的)使用它们与 If else 语句相比有什么好处?
采纳答案by Jerry Coffin
"Correctly" is a value judgment, but (unlike other classes) there's a major benefit from exceptions classes being a monolithic hierarchy, so I'd generally advise throwing something derived from std::exception
, notsimply an int.
“正确”是一种价值判断,但是(与其他类不同)异常类是一个整体层次结构的一个主要好处,所以我通常建议抛出从 派生的东西std::exception
,而不仅仅是一个 int。
Second, it's open to question whether an incorrect file name is sufficiently unexpected to qualify as a good reason to throw an exception at all.
其次,不正确的文件名是否足以出乎意料,足以成为引发异常的充分理由,这是值得怀疑的。
As to benefits vs. an if/else statement: there are a couple. First, exceptions let you segregate the code that deals with errors, so the main idea and readability of the code don't get lost in a maze of error handling. Second, when you have several layers of code between throwing and catching the exception, the code that throws the exception may not know how it should really be handled. Your code, for example, uses std::cout
to report the problem -- but most such code would report errors on std::cerr
instead. You can change from one to the other without any change to the code that tried to open the file (which might be deep in a library, and have no clue of which should be used for this application -- and might be used in an application where both are wrong, and MessageBox
was preferred).
至于好处与 if/else 语句:有几个。首先,异常让您隔离处理错误的代码,因此代码的主要思想和可读性不会在错误处理的迷宫中迷失。其次,当你在抛出和捕获异常之间有几层代码时,抛出异常的代码可能不知道应该如何真正处理它。例如,您的代码用于std::cout
报告问题——但大多数此类代码反而会报告错误std::cerr
。您可以从一个更改为另一个,而无需对尝试打开文件的代码进行任何更改(这些代码可能位于库的深处,并且不知道哪个应该用于此应用程序——并且可能在应用程序中使用)两者都是错误的,并且MessageBox
是首选)。
回答by Billy ONeal
First I would like to know if I am using Exceptions correctly.
Yes, though generally you want your exceptions to derive from std::exception.
首先,我想知道我是否正确使用了异常。
是的,尽管通常您希望您的异常从 std::exception 派生。
Second, (assuming the first is true) what is the benefit to using them vs an If else statement?
For the given example, nothing. The benefit of exceptions comes when you have
many deep nested functions, like this.
其次,(假设第一个是真的)使用它们与 If else 语句相比有什么好处?
对于给定的示例,什么都没有。当您有许多像这样的深层嵌套函数时,异常的好处就来了。
#include <stdexcept>
#include <iostream>
#include <string>
void anErrorFunc(const std::string& x)
{
ifstream file;
file.open(x);
if (!file)
throw std::runtime_error("Could not open file");
}
void someOtherFunction(const std::string& y)
{
//Do stuff
anErrorFunc(y);
//Do other stuff
}
int main()
{
try {
someOtherFunction("somefile.txt");
} catch (std::exception &ex) {
std::cout << "Ouch! That hurts, because: "
<< ex.what() << "!\n";
}
}
Note that the exception will be caught in main()
, and someOtherFunction
does not have to worry about dealing with passing through failure return codes.
注意异常会在 中被捕获main()
,someOtherFunction
不必担心处理传递失败返回码。
回答by Michael Aaron Safyan
Well, you are using exception correctly in that there is nothing wrong with your code. That said, typically we do not throw primitive types around (even though you can). It is generally a better idea to throw an object that derives from std::exception, and even better to throw an std::exception that is also a boost::exception.
好吧,您正确地使用了异常,因为您的代码没有任何问题。也就是说,通常我们不会抛出原始类型(即使你可以)。抛出从std::exception派生的对象通常是一个更好的主意,甚至更好的是抛出一个也是boost::exception的 std ::exception。
When things are very simple and the handling code and the throwing code are in the same function, then there really is no reason to use exceptions instead of if statements (and, indeed, it would be faster and more efficient to use if...else in that particular case). However, in most situations, the point where the error is discovered and you need to report it is far removed from the logic where the error is to be handled. In many cases the error-recovery logic is specific to the application in question and the logic where the error is discovered cannot make a sensible choice about how to recover from the error, hence the need to throw.
当事情非常简单并且处理代码和抛出代码在同一个函数中时,真的没有理由使用异常而不是 if 语句(而且,确实,使用 if ...否则在这种特殊情况下)。但是,在大多数情况下,发现错误并需要报告的点与要处理错误的逻辑相去甚远。在许多情况下,错误恢复逻辑特定于所讨论的应用程序,发现错误的逻辑无法就如何从错误中恢复做出明智的选择,因此需要抛出。
Another benefit of exception handling is that the type of the exception can be used to convey the type of error that occurred. Usually the types in exception hierarchies are much more meaningful than those error codes that end up being used in C code. Also, you cannot ignore an exception as easily as you can ignore an error code; while you can ignore an exception, it will cause the program to die a horrible death. By contrast, if a C function returns an error status code, and you ignore it, it's possible to continue executing and get silently wrong results... in that sense, the use of exceptions is much safer than using error codes.
异常处理的另一个好处是异常的类型可用于传达发生的错误的类型。通常,异常层次结构中的类型比最终在 C 代码中使用的那些错误代码更有意义。此外,您不能像忽略错误代码一样轻松地忽略异常;虽然您可以忽略异常,但它会导致程序死亡。相比之下,如果一个 C 函数返回一个错误状态代码,而你忽略它,它可能会继续执行并得到错误的结果......从这个意义上说,使用异常比使用错误代码安全得多。
You may also be interested in reading about exceptions and error handling from the C++ FAQ Lite.
您可能还对阅读C++ FAQ Lite 中有关异常和错误处理的内容感兴趣。
回答by Daniel Daranas
You are not using exceptions correctly. Your code has a much simpler equivalent, without exceptions, which provides the same behaviour.
您没有正确使用异常。您的代码有一个更简单的等效代码,无一例外,它提供了相同的行为。
Exceptions are for when you can'ttest the results of a function call with other methods. In this case you can, so you shouldn't use exceptions.
例外情况是您无法使用其他方法测试函数调用的结果。在这种情况下你可以,所以你不应该使用异常。
As a corollary, you shouldn't throw and catch the exception in the same function body - just do whatever you want to do insteadof throwing it.
作为推论,您不应该在同一个函数体中抛出和捕获异常——只要做任何你想做的事情,而不是抛出它。
回答by wilhelmtell
Syntactically speaking, your code is correct. Idiomatically speaking, maybe not so much -- or at least this depends on the context. When a file can't open then we might do our handling right there inside that if( !file.good() )
if it's perfectly common and possible to happen. For example, if the user asks to open a file in a text editor then it's perfectly plausible and common that the file doesn't exist. On the other hand, if the editor can't find the spelling corpus file then that means something is (arguably) terribly wrong. The program wasn't probably installed, or the user messed around with that file -- anything is possible.
从语法上讲,您的代码是正确的。用惯用语来说,可能不是那么多——或者至少这取决于上下文。当文件无法打开时,if( !file.good() )
如果它非常常见并且可能发生,我们可能会在里面进行处理。例如,如果用户要求在文本编辑器中打开一个文件,那么该文件不存在是完全合理且常见的。另一方面,如果编辑器找不到拼写语料库文件,那么这意味着某些东西(可以说)非常错误。该程序可能没有安装,或者用户弄乱了该文件——一切皆有可能。
In C++ we use exceptions for exceptional cases. That is, cases that are really not meant to happen and that we don't "accept" to happen. This is as opposed to a user file not opening, or an invalid user input, or no internet connection: these are all examples of perfectly valid things happening, common situations, things we expect to happen sooner or later in a program's run. They aren't exceptional.
在 C++ 中,我们对异常情况使用异常。也就是说,那些真的不打算发生并且我们不“接受”发生的情况。这与未打开的用户文件、无效的用户输入或没有互联网连接相反:这些都是完全有效的事情发生的例子,常见情况,我们预计在程序运行中迟早会发生的事情。他们并不例外。
Now, what are the benefits of using exceptions compared to conditionals? Allow me to extend this question to any other jump (goto
) mechanism: returns as well as conditionals. Exceptions are more expressive if that's what you want to say: if you are dealing with an exceptional case then use exceptions. Exceptions also get more done than plain conditionals, in an analogous way to that of virtual functions getting more done than conditionals. The right code-block will be executed depending on the exception, but also the right scopewill handle the exception depending on the handlers.
现在,与条件相比,使用异常有什么好处?请允许我将此问题扩展到任何其他跳转 ( goto
) 机制:返回以及条件。如果这就是您要说的,则异常更具表现力:如果您正在处理异常情况,则使用异常。异常也比普通条件完成的更多,类似于虚函数比条件完成更多的工作。正确的代码块将根据异常执行,但正确的范围将根据处理程序处理异常。
There are other advantages to exceptions compared with conditionals: exceptions separate error-handling from other code. They allow associating arbitrary data and actions with an error state. They allow communicating success states (via a return
) as well as error state (via a throw
). And the list goes on...
与条件相比,异常还有其他优点:异常将错误处理与其他代码分开。它们允许将任意数据和操作与错误状态相关联。它们允许通信成功状态(通过 a return
)以及错误状态(通过 a throw
)。而这样的例子不胜枚举...
Technically speaking and at the lowest level exceptions are a sophisticated jump mechanism. Back in the butterfly-dayspeople invented the if
conditional as a somewhat-sophisticated goto
in order to enhance expressiveness (because a goto
can be used for anything really) and to reduce programmer errors. The looping constructs such as the C for
loop are also in essence a sophisticated jump with sparkles and rainbow colours, again for reducing errors and enhancing expressiveness. C++ introduced its new casting operators for the same reasons.
从技术上讲,在最低级别的异常是一种复杂的跳转机制。早在蝴蝶时代,人们发明了if
条件作为一种有点复杂的方式goto
,以增强表现力(因为 agoto
可以用于任何事情)并减少程序员错误。循环结构(例如 Cfor
循环)本质上也是一种复杂的跳跃,带有闪光和彩虹色,同样是为了减少错误并增强表现力。出于同样的原因,C++ 引入了新的强制转换运算符。
So there: exceptions aren't magic, just something somewhat new in the scene compared to conditionals and loops. Don't use them when you don't mean to, just like you don't use a loop when you really mean to use a conditional.
所以:异常不是魔法,只是场景中与条件和循环相比有些新的东西。不要在无意时使用它们,就像当你真的要使用条件时不要使用循环一样。
回答by JUST MY correct OPINION
Syntactically what you're doing is right. Style-wise, as others have noted, you should be throwing something descended from std::exception.
从语法上讲,您所做的是正确的。在风格方面,正如其他人所指出的,你应该抛出一些源自 std::exception 的东西。
As to part two of your question, I'd like to go into more detail on that.
至于你问题的第二部分,我想更详细地说明一下。
The whole point of exceptions is to separate policy from implementation. As Billy ONeal said, you get no benefit at all from using exceptions within the same function that an if
statement wouldn't make better. You need to be deeply nested in function calls for it to make sense.
例外的全部意义在于将政策与实施分开。正如 Billy ONeal 所说,在同一个函数中使用异常if
不会让语句变得更好,你根本没有任何好处。您需要深入嵌套在函数调用中才能使其有意义。
In most code, your high level code has enough information and context to know what to do about errors, but no mechanism to detect them. Your low level code can detect the errors but has none of the information needed to deal with them.
在大多数代码中,您的高级代码具有足够的信息和上下文来了解如何处理错误,但没有检测它们的机制。您的低级代码可以检测到错误,但没有处理它们所需的任何信息。
The traditional means of coping with this -- returning error codes -- has a few problems:
解决这个问题的传统方法——返回错误代码——有一些问题:
- It clutters up the code with error handling code to the point that the actual logic is obfuscated.
- It relies on programmers not being lazy and checking EVERY error code return, an often foolhardy assumption. (C programmers, be honest here: when was the last time you checked the return value of
printf
?) - It adds the overhead of error checking and handling to EVERY function call whether there's an error or not.
- 它用错误处理代码把代码弄得乱七八糟,以至于混淆了实际的逻辑。
- 它依赖于程序员不偷懒并检查每个错误代码返回,这是一个经常鲁莽的假设。(C 程序员,老实说:你最后一次检查 的返回值是
printf
什么时候?) - 无论是否有错误,它都会为每个函数调用增加错误检查和处理的开销。
Exceptions solve these issues (with varying degrees of success).
例外解决了这些问题(取得了不同程度的成功)。
- Exceptions solve #1 by only having exception-related code at the point of detection and at the point of handling. Intervening functions don't get cluttered with handling for obscure errors that they themselves have no interest in nor capability of dealing with.
- They solve #2 by forcing handling. You can't ignore an exception. You have to take action on them. (Lazy programmers can still catch all exceptions and then ignore them, but here their crippling inability to program is now highlighted for all to see.)
- They solve #3 (when not naively implemented) by having near-zero costs when not used, albeit often at a very, very high cost when actually used.
- 异常通过在检测点和处理点仅具有与异常相关的代码来解决 #1。中间函数不会因为处理它们自己没有兴趣也没有能力处理的晦涩错误而变得混乱。
- 他们通过强制处理来解决#2。您不能忽略异常。你必须对他们采取行动。(懒惰的程序员仍然可以捕获所有异常然后忽略它们,但在这里,他们严重的编程能力现在突出显示给所有人看。)
- 他们通过在不使用时接近零的成本来解决 #3(当没有天真地实施时),尽管在实际使用时通常成本非常非常高。
This is not to say that exceptions are the end-all/be-all of error handling. The disadvantages:
这并不是说异常是错误处理的全部/全部。缺点:
- Exceptions are usually very costly when used. They have to be eschewed, despite their advantages, if performance is paramount.
- Exceptions lead to very opaque code at times. They are non-localtransfers of control -- effectively slightly safer versions of
goto
statements, but across functions. An exception can transfer control from hundreds of layers deep in your code in source files not even slightly related to the ones you're working on (and, in fact, quite possibly not even accessible to you). This kind of "spooky action at a distance" can make code very difficult to figure out. - "Checked exceptions" can actually be worse for noise generation than the old-style
if
handling. They tend to be more verbose, you see, thanif
orswitch
statements and the fact that you musthandle checked exceptions for the code to even compile makes them a liability to many situations. - Because of their often high cost of use, carelessly using them for all error handling can make your code slow and bloated.
- 异常在使用时通常非常昂贵。尽管它们具有优势,但如果性能至上,则必须避免使用它们。
- 异常有时会导致非常不透明的代码。它们是控制的非本地转移——实际上是稍微安全的
goto
语句版本,但跨函数。异常可以从源文件中代码深处的数百层转移控制权,甚至与您正在处理的文件几乎没有关系(实际上,您甚至可能无法访问)。这种“幽灵般的远距离动作”会使代码很难弄清楚。 - “检查异常”实际上比旧式
if
处理更容易产生噪音。你看,它们往往比if
orswitch
语句更冗长,而且你必须处理检查异常才能编译代码的事实使它们在许多情况下成为一种负担。 - 由于它们的使用成本通常很高,不小心将它们用于所有错误处理可能会使您的代码变慢和臃肿。