C++中如何进行异常处理?有哪些方式处理异常?

2021年4月3日19:22:13 发表评论 964 次浏览

与C相比, C++的优点之一是异常处理。异常是程序在执行过程中遇到的运行时异常或异常情况。异常有两种类型:a)同步, b)异步(例如:超出程序的控制范围, 光盘故障等)。为此, C++提供了以下专用关键字。

try:表示可能引发异常的代码块。

catch:表示抛出特定异常时执行的代码块。

throw:用于引发异常。也用于列出函数抛出但无法自行处理的异常。

为什么要进行异常处理?

以下是异常处理相对于传统错误处理的主要优点。

1)错误处理代码与普通代码的分离:在传统的错误处理代码中, 总是存在其他条件来处理错误。这些条件和处理错误的代码与正常流程混在一起。这使代码的可读性和可维护性较差。使用try catch块, 用于错误处理的代码将与正常流程分开。

2)函数/方法可以处理他们选择的任何异常:

函数可以引发许多异常, 但可以选择处理其中一些异常。引发但未被捕获的其他异常可以由调用方处理。如果呼叫者选择不捕获它们, 则异常由呼叫者的呼叫者处理。

在C++中, 函数可以使用throw关键字指定其引发的异常。此函数的调用者必须以某种方式处理异常(通过再次指定它或捕获它)

3)错误类型分组:在C++中, 基本类型和对象都可以作为异常抛出。我们可以创建异常对象的层次结构, 在名称空间或类中对异常进行分组, 并根据类型对它们进行分类。

C++中的异常处理

1)以下是显示C++中异常处理的简单示例。程序的输出说明了try / catch块的执行流程。

#include <iostream>
using namespace std;
  
int main()
{
    int x = -1;
  
    // Some code
    cout << "Before try \n" ;
    try {
       cout << "Inside try \n" ;
       if (x < 0)
       {
          throw x;
          cout << "After throw (Never executed) \n" ;
       }
    }
    catch ( int x ) {
       cout << "Exception Caught \n" ;
    }
  
    cout << "After catch (Will be executed) \n" ;
    return 0;
}

输出如下:

Before try
Inside try
Exception Caught
After catch (Will be executed)

2)有一个特殊的catch块, 称为" catch all" catch(…), 可用于捕获所有类型的异常。例如, 在下面的程序中, 将引发int作为异常, 但是没有用于int的catch块, 因此将执行catch(…)块。

#include <iostream>
using namespace std;
  
int main()
{
     try  {
        throw 10;
     }
     catch ( char *excp)  {
         cout << "Caught " << excp;
     }
     catch (...)  {
         cout << "Default Exception\n" ;
     }
     return 0;
}

输出如下:

Default Exception

3)原始类型不会发生隐式类型转换。例如, 在以下程序中, " a"未隐式转换为int

#include <iostream>
using namespace std;
  
int main()
{
     try  {
        throw 'a' ;
     }
     catch ( int x)  {
         cout << "Caught " << x;
     }
     catch (...)  {
         cout << "Default Exception\n" ;
     }
     return 0;
}

输出如下:

Default Exception

4)如果引发了异常且未在任何地方捕获异常, 则程序异常终止。例如, 在下面的程序中, 抛出了一个char, 但是没有catch块来捕获char。

#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()的签名应列出未检查的异常。

#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()

编写以上代码的更好方法

#include <iostream>
using namespace std;
  
// Here we specify the exceptions that this function 
// throws.
void fun( int *ptr, int x) throw ( int *, int )"
{
     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()

8)在C++中, 可以嵌套try-catch块。另外, 可以使用" throw; throw; throw"来重新抛出异常。 "

#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; throw"来重新抛出一个函数。 "。一个函数可以处理一部分, 并且可以要求调用方处理剩余部分。

9)当引发异常时, 在将控制转移到catch块之前, 将破坏在try块内部创建的所有对象。

#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 Test
Destructor of Test
Caught 10

10)你可能想尝试C++中异常处理的测验.

如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: