C++中的异常处理

C++在C上的优势之一是异常处理。异常是程序在执行过程中遇到的运行时异常或异常情况。有两种类型的异常:a)同步,b)异步(例如:程序无法控制,磁盘故障等)。C++提供了以下专门的关键字。 尝试 :表示可以引发异常的代码块。 接住 :表示在引发特定异常时执行的代码块。 :用于引发异常。还用于列出函数抛出但不自行处理的异常。

null

为什么要处理异常? 以下是异常处理相对于传统错误处理的主要优势。

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++异常处理的问答 . 如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享