[英]Correct Exceptions in C++
我只是学习如何处理我的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;
}
现在我有两个问题。 首先,我想知道我是否正确使用了例外。 第二,(假设第一个是真的)使用它们对If else语句有什么好处?
“正确地”是一个值判断,但是(与其他类不同),异常类是一个单一的层次结构有一个主要的好处,所以我通常建议抛出从std::exception
派生的东西, 而不仅仅是一个int。
其次,可以肯定的是,不正确的文件名是否足够意外,无法作为抛出异常的理由。
至于利益与if / else声明:有一对。 首先,异常允许您隔离处理错误的代码,因此代码的主要思想和可读性不会在错误处理的迷宫中丢失。 其次,当你在抛出和捕获异常之间有几层代码时,抛出异常的代码可能不知道应该如何处理它。 例如,您的代码使用std::cout
来报告问题 - 但大多数此类代码会报告std::cerr
上的错误。 您可以从一个更改为另一个,而无需对尝试打开文件的代码进行任何更改(可能在库中很深,并且不知道哪个应该用于此应用程序 - 并且可能在应用程序中使用两者都错了,而MessageBox
是首选)。
首先,我想知道我是否正确使用了例外。
是的,但通常您希望您的异常派生自std :: exception。
第二,(假设第一个是真的)使用它们对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";
}
}
请注意,异常将在main()
捕获,而someOtherFunction
不必担心处理传递失败返回代码。
好吧,您正确使用异常,因为您的代码没有任何问题。 也就是说,通常我们不会抛出原始类型(即使你可以)。 抛出一个派生自std :: exception的对象通常更好一点,甚至更好地抛出一个同样是boost :: exception的std :: exception 。
当事情非常简单并且处理代码和抛出代码在同一个函数中时,实际上没有理由使用异常而不是if语句(事实上,如果......使用它会更快更有效率)否则在那个特殊情况下)。 但是,在大多数情况下,发现错误并且需要报告错误的点远离要处理错误的逻辑。 在许多情况下,错误恢复逻辑特定于所讨论的应用程序,并且发现错误的逻辑无法做出关于如何从错误中恢复的明智选择,因此需要抛出。
异常处理的另一个好处是异常的类型可用于传达发生的错误类型。 通常,异常层次结构中的类型比最终在C代码中使用的那些错误代码更有意义。 此外,您不能轻易忽略异常,因为您可以忽略错误代码; 虽然你可以忽略一个例外,它会导致程序死于可怕的死亡。 相比之下,如果C函数返回错误状态代码,并且您忽略它,则可以继续执行并获得静默错误的结果......从这个意义上说,使用异常比使用错误代码更安全。
您可能还有兴趣阅读C ++ FAQ Lite中的异常和错误处理 。
您没有正确使用异常。 您的代码具有更简单的等价物,没有例外,它提供相同的行为。
例外情况是指您无法使用其他方法测试函数调用的结果。 在这种情况下你可以,所以你不应该使用例外。
作为必然结果,你不应该在同一个函数体中抛出并捕获异常 - 只需做你想做的事情而不是抛出它。
从语法上讲,您的代码是正确的。 习惯上说,也许不是那么多 - 或者至少这取决于背景。 当一个文件无法打开时,我们可能会在那里进行处理if( !file.good() )
如果它是完全常见的并且可能发生。 例如,如果用户要求在文本编辑器中打开文件,那么该文件不存在就完全合理且常见。 另一方面,如果编辑器找不到拼写语料库文件,那么这意味着(可以说)非常错误。 该程序可能没有安装,或者用户弄乱了该文件 - 一切皆有可能。
在C ++中,我们对异常情况使用异常。 也就是说,这些案件实际上并非意味着发生,而且我们并不“接受”这种情况。 这与用户文件未打开,无效用户输入或无互联网连接相反:这些都是完全有效的事情发生的例子,常见情况,我们期望在程序运行中迟早发生的事情。 它们并非例外 。
现在,与条件相比,使用异常有什么好处? 请允许我将此问题扩展到任何其他跳转( goto
)机制:返回以及条件。 如果您想说的话,例外情况会更具表现力:如果您正在处理特殊情况,则使用例外。 异常也比普通条件更多地完成,其方式类似于虚函数比条件更多的完成。 正确的代码块将根据异常执行,但正确的范围将根据处理程序处理异常。
与条件相比,异常还有其他优点:异常将错误处理与其他代码分开。 它们允许将任意数据和操作与错误状态相关联。 它们允许通信成功状态(通过return
)以及错误状态(通过throw
)。 而这样的例子不胜枚举...
从技术上讲,在最低级别,异常是一种复杂的跳跃机制。 回到蝴蝶日,人们发明了if
条件作为一个有点复杂的goto
,以增强表达力(因为goto
可以用于任何真正的东西)并减少程序员错误。 诸如C for
循环之类的循环结构本质上也是具有闪光和彩虹色的复杂跳跃,同样用于减少错误和增强表现力。 出于同样的原因,C ++引入了新的铸造运算符。
所以:异常不是魔术,只是与条件和循环相比,场景中有些新东西。 当你不打算使用时,不要使用它们,就像你真的想要使用条件时不使用循环一样。
从语法上讲,你所做的是正确的。 风格方面,正如其他人所指出的那样,你应该抛出std :: exception的后代。
关于你的问题的第二部分,我想详细介绍一下。
例外的全部内容是将政策与实施分开。 正如Billy ONeal所说,在if
语句不能做得更好的同一函数中使用异常完全没有任何好处。 你需要在函数调用中深深嵌套它才有意义。
在大多数代码中,您的高级代码具有足够的信息和上下文来知道如何处理错误,但没有检测它们的机制。 您的低级代码可以检测到错误,但没有处理它们所需的信息。
应对此问题的传统方法 - 返回错误代码 - 存在一些问题:
printf
的返回值是什么时候?) 例外解决了这些问题(取得了不同程度的成功)。
这并不是说异常是错误处理的最终/全部。 缺点:
goto
语句版本,但是跨功能。 一个例外可以在源代码文件中从代码深处的数百个层转移控制,甚至与您正在处理的文件略有关系(实际上,甚至很可能无法访问)。 这种“远距离的怪异行为”可能使代码很难弄明白。 if
处理。 你看,它们往往比if
或switch
语句更加冗长,而且你必须处理代码的已检查异常以进行编译,这使得它们成为许多情况的责任。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.