c++異常處理機制
C++異常處理機制是一個用來有效地處理運行錯誤的非常強大且靈活的工具,它提供了更多的彈性、安全性和穩固性,克服了傳統方法所帶來的問題.
異常的拋出和處理主要使用了以下三個關鍵字:?try、?throw?、?catch?。
拋出異常即檢測是否產生異常,在C++中,其采用throw語句來實現,如果檢測到產生異常,則拋出異常。該語句的格式為:
throw?表達式;
如果在try語句塊的程序段中(包括在其中調用的函數)發現了異常,且拋棄了該異常,則這個異常就可以被try語句塊后的某個catch語句所捕獲并處 理,捕獲和處理的條件是被拋棄的異常的類型與catch語句的異常類型相匹配。由于C++使用數據類型來區分不同的異常,因此在判斷異常時,throw語 句中的表達式的值就沒有實際意義,而表達式的類型就特別重要。
try-catch語句形式如下 :
try
{
????????包含可能拋出異常的語句;
}
catch(類型名?[形參名])?//?捕獲特定類型的異常
{
}
catch(類型名?[形參名])?//?捕獲特定類型的異常
{
}
catch(...)????//?三個點則表示捕獲所有類型的異常
{
}
【范例1】處理除數為0的異常。該范例將上述除數為0的異常可以用try/catch語句來捕獲異常,并使用throw語句來拋出異常,從而實現異常處理,實現代碼如代碼清單1-1所示。
//?代碼清單1-1
1????????#include<iostream.h>?????//包含頭文件
2????????#include<stdlib.h>
3????????double?fuc(double?x,?double?y)?//定義函數
4????????{
5????????????????if(y==0)
6????????????????{
7????????????????????????throw?y;?????//除數為0,拋出異常
8????????????????}
9????????????????return?x/y;?????//否則返回兩個數的商
10????????}
11????????void?main()
12????????{
13????????????????double?res;
14????????????????try?????????????????//定義異常
15????????????????{
16????????????????????????res=fuc(2,3);
17????????????????????????cout<<"The result of x/y is : "<<res<<endl;
18????????????????????????res=fuc(4,0);????????//出現異常,函數內部會拋出異常
19????????????????}
20????????????????catch(double)?????????????//捕獲并處理異常 【throw y的類型為double,捕獲的類型為double】
21????????????????{
22????????????????????????cerr<<"error of dividing zero./n";
23????????????????????????exit(1);????????????????//異常退出程序
24????????????????}
25????????}
【范例2】自定義異常類型 (在本文開始的代碼中已經給出示范)
三、異常的接口聲明
為了加強程序的可讀性,使函數的用戶能夠方便地知道所使用的函數會拋出哪些異常,可以在函數的聲明中列出這個函數可能拋出的所有異常類型,例如:
void?fun()?throw( A,B,C,D);
這表明函數fun()可能并且只可能拋出類型(A,B,C,D)及其子類型的異常。
如果在函數的聲明中沒有包括異常的接口聲明,則此函數可以拋出任何類型的異常,例如:
void?fun();
一個不會拋出任何類型異常的函數可以進行如下形式的聲明:
void?fun() thow();
??????
五、異常處理中需要注意的問題
1.?如果拋出的異常一直沒有函數捕獲(catch),則會一直上傳到c++運行系統那里,導致整個程序的終止
2.?一般在異常拋出后資源可以正常被釋放,但注意如果在類的構造函數中拋出異常,系統是不會調用它的析構函數的,處理方法是:如果在構造函數中要拋出異常,則在拋出前要記得刪除申請的資源。
3.?異常處理僅僅通過類型而不是通過值來匹配的,所以catch塊的參數可以沒有參數名稱,只需要參數類型。
4.?函數原型中的異常說明要與實現中的異常說明一致,否則容易引起異常沖突。
5.?應該在throw語句后寫上異常對象時,throw先通過Copy構造函數構造一個新對象,再把該新對象傳遞給?catch.?
那么當異常拋出后新對象如何釋放?
異常處理機制保證:異常拋出的新對象并非創建在函數棧上,而是創建在專用的異常棧上,因此它才可以跨接多個函數而傳遞到上層,否則在棧清空的過程中就會被 銷毀。所有從try到throw語句之間構造起來的對象的析構函數將被自動調用。但如果一直上溯到main函數后還沒有找到匹配的catch塊,那么系統 調用terminate()終止整個程序,這種情況下不能保證所有局部對象會被正確地銷毀。
6. catch塊的參數推薦采用地址傳遞而不是值傳遞,不僅可以提高效率,還可以利用對象的多態性。另外,派生類的異常撲獲要放到父類異常撲獲的前面,否則,派生類的異常無法被撲獲。
7.?編寫異常說明時,要確保派生類成員函數的異常說明和基類成員函數的異常說明一致,即派生類改寫的虛函數的異常說明至少要和對應的基類虛函數的異常說明相同,甚至更加嚴格,更特殊。