C++异常(1) - 异常介绍

来源:互联网 发布:java ee eclipse 编辑:程序博客网 时间:2024/05/23 21:57
相比C语言, C++的一个优势是提供了异常处理机制。定义了相关的关键字。

try: 代表可以抛出异常的代码块

catch: 用于处理抛出的一个特定异常的代码块。

throw: 处于抛出一个异常。也可以用于一个函数抛出的异常列表。

为何需要异常处理?

下面是异常处理比传统错误处理的优势:

1. 可以将处理错误的代码与正常代码分离开:传统错误处理代码中,通常包含if else条件判断。这些处理错误的条件代码与正常代码会混合在一起。降低了代码的可读性与可维护性。使用try catch代码块,可以将处理异常的代码与正常代码分离开。

2. 函数/方法可以处理他们所选择的任何异常:一个函数可以抛出多种异常,但是可以选择只处理其中的一些。另外的一些,可以交由调用者来处理。如果调用者选择不处理这些异常,可以抛给上外层的调用者去处理。
C++中,一个函数可以使用throw关键字来指定它要抛的异常。此函数的调用者必须采取某些方式来处理异常(或者继续指定异常,或者捕获它)。

3. 错误类型的组合: C++中, 基本类型和对象都能当作异常抛出。我们可以创建异常对象的组合,将异常在namespace或class中分组,按照类型进行分类。

C++的异常处理

1) 下面是一个简单演示。 输出结果解释了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 tryInside tryException CaughtAfter catch (Will be executed)

2) 有一个特殊的catch代码块,称为'catch call'。catch(...)可以用来捕获所有类型的异常。
例如,下面程序中抛出了一个异常,但是没有catch代码块来捕获int类型,所以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 (C++中‘a'代表一个字符, 而C中是一个整数).

#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) 如果抛出了异常,但是没有任何地方捕获,则程序会异常的终止。
例如,下面程序会终止。
#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.

我们可以使用自己定义的异常函数来替换这个异常终止的行为。
详细参考这个链接:http://www-01.ibm.com/support/knowledgecenter/SSXVZZ_8.0.0/com.ibm.xlcpp8l.doc/language/ref/cplr162.htm%23CPLR162

5) 子类的异常应该在基类异常之前被捕获。参考"C++异常(3) - xxx"

6) 与Java类似, C++库中也定义了一个标准异常处理类,它是所有其它标准类的基类。标准库中抛出的所有异常对象都是继承自这个类。因此,所有的标准异常都能使用这个类型来进行捕获。

7) 不同于Java,C++中所有异常是不检查的。编译器不会检查一个异常是否被捕获。例如函数声明时不需要指出所有不会被捕获的异常,尽管推荐这么做。
例子:下面程序编译正常,但是严格来说fun()应该列出它不会检测的异常。
#include <iostream>using namespace std;// 此函数的实现,对于编译器没什么问题,但是不推荐这么做。// 理论上,此函数应该列出所有不会捕获的异常,并且函数名应该为// "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;} int main(){    try {       fun(NULL, 0);    }    catch(...) {        cout << "Caught exception from fun()";    }    return 0;}
输出:
Caught exception from fun()

8) C++中try-catch代码块是可以嵌套的。另外,一个异常可以使用throw重新抛出。

#include <iostream>using namespace std; int main(){    try{        try {            throw20;        }        catch(int n) {             cout <<"Handle Partially\n";             throw;  // 再次抛出异常        }    }    catch(int n) {        cout <<"Handle remaining\n";    }    return 0;}

输出:
Handle Partially 
Handle remaining
函数中也可以使用throw重新抛出异常。也可以只部分处理,然后请求调用者来处理剩余部分。

9) 当抛出了一个异常时。try代码块中创建的所有对象都会被析构掉,在将控制权转移到catch代码块之前。

#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

0 0
原创粉丝点击