首页 > 编程笔记 > C++笔记 阅读:14

C++中的异常处理机制(新手必看)

在程序运行过程中,外界环境的异常情况可能引发程序执行出错,导致错误的结果。

例如,程序试图打开一个未被占用的文件进行写入,在正常情况下可以成功执行。但如果文件已被占用,程序就会执行失败。这种不正常的情况就是所谓的程序执行过程中的异常。常见的异常情况还包括数组下标越界、系统内存不足、以 0 作为除数等。

一旦程序执行过程中发生异常,可能会引发计算失效、程序运行时无故停止,甚至程序崩溃等严重后果。这些异常情况,虽然像现实世界中的地震一样无法避免且难以预料,但我们可以在开发程序时进行必要的异常处理,以降低用户的损失。

C++ 专门提供了异常处理机制,这是一种在运行时对出现的异常情况进行捕获并处理的方法。

C++ 中的异常处理使用 try 关键字来尝试执行可能会出现异常的代码段。当代码段执行过程中发生异常时,系统会抛出相应类型的异常。随后,catch 关键字会对异常进行捕获,并由相应类型的异常处理分支对其进行恰当的处理,如结束正在执行的操作、清理不再需要的资源等,从而避免更大错误的发生,尽可能地挽回用户的损失。

在 C++ 中,异常处理的基本语法格式如下:
// 用 try 开始异常处理语句
try
{
    // 可能发生异常的语句
}
catch(异常类型 [形参名])    // 捕获特定类型的异常
{
    // 对此类型的异常进行处理
}
catch(异常类型 [形参名])    // 捕获特定类型的异常
{
    // 对此类型的异常进行处理
}
// 可以有多个 catch 语句并列,捕获不同类型的异常
catch(...)    // 如果省略具体的异常类型用...表示,则表示捕获所有类型的异常
{
    // 对所有类型的异常进行处理
}
当我们认为某段代码可能会出现异常情况并需要处理时,可以把这段代码放入 try 关键字后面的代码块中。在程序执行 try 语句块中的语句(包括其中调用的函数)时,如果遇到异常情况,可以使用 throw 关键字抛出一个相应类型的异常,表示某种异常情况的发生,需要后面的 catch 语句捕获并对其进行处理。

用 throw 关键字抛出一个异常的语法格式如下:
throw 异常表达式;
其中,异常表达式就是要抛出的异常,它可以是表示异常类型的错误代码,或者是含有异常相关信息的某个对象,总之,它的意义是为异常处理提供相应的辅助信息。

例如:
// 除法函数
double Divide(int a, int b)
{
    if(0 == b)
        throw "不能使用 0 作为除数";

    return (double)a/b;
}
在这个除法函数中,当检测到除数为 0 时,使用 throw 关键字抛出一个异常,以提前结束这个函数,跳过后面的除法运算,避免错误的发生。这里 throw 关键字抛出的异常是一个字符串,它描述了异常发生的原因,便于程序员对其进行处理。当然,还可以抛出专门的异常对象,只要该异常对象的类型是事先定义好的,并能够给后面的异常处理提供足够的信息即可。

当 try 语句块中抛出某个类型的异常后,该异常会被紧跟其后的相应类型的 catch 语句捕获并对其进行处理。catch 语句可以带有一个形式参数,它的类型就是 catch 语句要捕获的异常类型,也就是说,异常被某个 catch 语句捕获的条件是该异常的类型与 catch 语句的异常类型相匹配。

当 throw 关键字抛出的异常被某个 catch 语句捕获时,throw 关键字后的异常表达式会被当成实际参数传递给 catch 语句中的形式参数,进而 catch 语句可以根据这个参数提供的信息对异常进行具体的处理。

当需要捕获多种类型的异常时,可以将多个 catch 语句并列。如果省略 catch 关键字后面的形式参数而使用…代替,则表示 catch 语句会捕获所有类型的异常。

当 try 语句块中抛出异常并被某个 catch 分支捕获后,异常处理会把程序的执行从异常发生的地点转移到捕获这个异常的 catch 分支语句,随后对异常进行具体的处理。

例如:
// 开始异常处理语句
try
{
    cout<<"请输入被除数与除数:"<<endl;
    int a,b;    // 被除数与除数
    cin>>a>>b;  // 接收用户输入
    // 进行除法运算,当 b 为 0 时会抛出异常
    double fRes = Divide(a, b);
    cout<<a<<"/"<<b<<" = "<<fRes<<endl;  // 输出结果
}
// 捕获 try 语句块中所抛出的字符串类型异常
catch( char* pMsg )
{
    // 对异常进行处理
    // 这里只输出错误信息
    cout<<"程序运行发生异常:"<<pMsg<<endl;
}
在这段代码中,我们使用 Divide() 函数来完成一个除法运算。但这个函数在除数为 0 的情况下会发生异常。为了确保程序的正确性和用户的友好使用体验,我们将除法运算放到 try 语句块中执行。

当异常发生时,也就是用户输入的除数为 0 时,Divide() 函数会抛出一个描述了错误信息的字符串类型的异常。在 try 语句块之后的 catch 语句会捕获这个字符串类型的异常并进行处理。有了异常处理,即使用户不小心输入了除数为 0,程序也不会直接给出一个错误结果,而是会提示用户错误的发生及其原因,帮助用户修复问题。这样可以提供良好的用户体验,避免用户对程序产生不满。

当然,这里对异常的处理只是将这个错误信息输出报告给用户而已。在实际应用中,异常处理往往更加复杂,包括资源的清理回收、记录错误日志等。

异常处理的三个步骤如下图所示:

图 1 异常处理的三个步骤

总之,使用异常处理这一方法,可以在错误发生后尽量补救错误所造成的损失,最大程度地减少对用户的影响,同时增强程序的健壮性,也让程序员少挨一点骂。

相关文章