C++在C上的优势之一是异常处理。异常是程序在执行过程中遇到的运行时异常或异常情况。有两种类型的异常:a)同步,b)异步(例如:程序无法控制,磁盘故障等)。C++提供了以下专门的关键字。 尝试 :表示可以引发异常的代码块。 接住 :表示在引发特定异常时执行的代码块。 投 :用于引发异常。还用于列出函数抛出但不自行处理的异常。
为什么要处理异常? 以下是异常处理相对于传统错误处理的主要优势。
1) 错误处理代码与正常代码的分离: 在传统的错误处理代码中,总是存在if-else条件来处理错误。这些条件和处理错误的代码会与正常流程混淆。这会降低代码的可读性和可维护性。使用try-catch块,错误处理的代码与正常流分离。
2) 函数/方法可以处理它们选择的任何异常: 一个函数可以抛出许多异常,但可以选择处理其中一些异常。其他抛出但未捕获的异常可以由调用方处理。如果调用者选择不捕获它们,那么异常将由调用者的调用者处理。 在C++中,函数可以使用抛出关键字指定抛出的异常。此函数的调用方必须以某种方式(通过再次指定或捕获)处理异常
3) 错误类型分组: 在C++中,基本类型和对象可以作为异常抛出。我们可以创建异常对象的层次结构,在名称空间或类中对异常进行分组,并根据类型对它们进行分类。
C++异常:
在执行C++代码时,可能会发生不同的错误:程序员编写的编码错误、错误输入引起的错误或其他不可预见的事情。
当发生错误时,C++通常会停止并生成错误消息。这个术语的技术术语是:C++会抛出异常(抛出错误)。
C++尝试与捕获:
C++中的异常处理由三个关键字组成:尝试、抛出和捕获:
try语句允许您定义一个代码块,以便在执行时对其进行错误测试。
当检测到问题时,throw关键字会抛出一个异常,这让我们可以创建一个自定义错误。
catch语句允许您在try块中发生错误时定义要执行的代码块。
try and catch关键字成对出现:
我们使用try块测试一些代码:如果age变量小于18,我们将抛出一个异常,并在catch块中处理它。
在catch块中,我们捕获错误并采取措施。catch语句使用一个参数:在我们的示例中,我们使用一个int变量(myNum)(因为我们在try块(age)中抛出一个int类型的异常)来输出age的值。
如果没有发生错误(例如,如果年龄是20岁而不是15岁,这意味着年龄将大于18岁),则跳过捕捉块:
C++中的异常处理
1) 下面是一个简单的例子,显示C++中的异常处理。程序的输出解释了try/catch块的执行流程。
CPP
#include <iostream> using namespace std; int main() { int x = -1; // Some code cout << "Before try " ; try { cout << "Inside try " ; if (x < 0) { throw x; cout << "After throw (Never executed) " ; } } catch ( int x ) { cout << "Exception Caught " ; } cout << "After catch (Will be executed) " ; return 0; } |
输出:
Before tryInside tryException CaughtAfter catch (Will be executed)
2) 有一个名为“catch all”catch(…)的特殊catch块,可用于捕获所有类型的异常。例如,在下面的程序中,int作为异常抛出,但是int没有catch块,所以catch(…)块将被执行。
CPP
#include <iostream> using namespace std; int main() { try { throw 10; } catch ( char *excp) { cout << "Caught " << excp; } catch (...) { cout << "Default Exception" ; } return 0; } |
输出:
Default Exception
3) 基本类型不会发生隐式类型转换。例如,在下面的程序中,“a”不是隐式转换为int
CPP
#include <iostream> using namespace std; int main() { try { throw 'a' ; } catch ( int x) { cout << "Caught " << x; } catch (...) { cout << "Default Exception" ; } return 0; } |
输出:
Default Exception
4) 如果抛出异常而未在任何地方捕获,则程序会异常终止。例如,在下面的程序中,会抛出一个char,但没有catch块来捕获char。
CPP
#include <iostream> using namespace std; int main() { try { throw 'a' ; } catch ( int x) { cout << "Caught " ; } return 0; } |
输出:
terminate called after throwing an instance of 'char'This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
我们可以通过以下方式改变这种异常终止行为: 编写我们自己意想不到的函数 . 5) 派生类异常应在基类异常之前捕获。看见 这 更多细节。 6) 与java一样,C++库也有 标准异常类 这是所有标准异常的基类。标准库组件抛出的所有对象都派生自此类。因此,可以通过捕获此类型来捕获所有标准异常 7) 与java不同,C++中所有的异常都是未选中的。编译器不会检查是否捕获了异常(请参阅) 这 详细信息)。例如,在C++中,不必在函数声明中指定所有未被排除的异常。尽管这是一种推荐的做法。例如,下面的程序编译得很好,但理想情况下,fun()的签名应该列出未检查的异常。
CPP
#include <iostream> using namespace std; // This function signature is fine by the compiler, but not recommended. // Ideally, the function should specify all uncaught exceptions and function // signature should be "void fun(int *ptr, int x) throw (int *, int)" void fun( int *ptr, int x) { if (ptr == NULL) throw ptr; if (x == 0) throw x; /* Some functionality */ } int main() { try { fun(NULL, 0); } catch (...) { cout << "Caught exception from fun()" ; } return 0; } |
输出:
Caught exception from fun()
编写上述代码的更好方法
CPP
#include <iostream> using namespace std; // Here we specify the exceptions that this function // throws. void fun( int *ptr, int x) throw ( int *, int ) // Dynamic Exception specification { if (ptr == NULL) throw ptr; if (x == 0) throw x; /* Some functionality */ } int main() { try { fun(NULL, 0); } catch (...) { cout << "Caught exception from fun()" ; } return 0; } |
( 注: 在C++11之后,动态异常规范的使用已被弃用,原因之一可能是它可以随机中止程序。当抛出动态异常规范中未提及的另一种类型的异常时,可能会发生这种情况,因为在这种情况下,程序调用(间接)terminate(),默认情况下调用abort())。
输出:
Caught exception from fun()
8) 在C++中,可以尝试嵌套块。此外,可以使用“throw;”重新抛出异常
CPP
#include <iostream> using namespace std; int main() { try { try { throw 20; } catch ( int n) { cout << "Handle Partially " ; throw ; // Re-throwing an exception } } catch ( int n) { cout << "Handle remaining " ; } return 0; } |
输出:
Handle Partially Handle remaining
函数还可以使用相同的“throw;”重新抛出函数。函数可以处理部分,也可以要求调用方处理剩余部分。 9) 抛出异常时,在将控件转移到catch块之前,在封闭的try块内创建的所有对象都会被销毁。
CPP
#include <iostream> using namespace std; class Test { public : Test() { cout << "Constructor of Test " << endl; } ~Test() { cout << "Destructor of Test " << endl; } }; int main() { try { Test t1; throw 10; } catch ( int i) { cout << "Caught " << i << endl; } } |
输出:
Constructor of TestDestructor of TestCaught 10
10) 你可以试试 C++异常处理的问答 . 如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。