C++异常详解
1.對異常的幾種處理方式
1)調用abort()
abort()函數的原型位于頭文件cstlib中,其實現是向標準錯誤流發送abnormal program termination(程序異常終止),然后終止程序。
示例如下:
2)返回錯誤碼
使用一個bool值來標記,運行結果是成功,還是失敗。
示例如下:
3)使用全局變量errno
出現異常時可以將全局變量errno設值,需要注意的是,要確保沒有其他的函數同時在使用這個全局變量
2.異常機制
涉及try,catch,throw關鍵字
示例代碼如下:
3.上面的示例中,我們拋出的是字符串,通常情況,我們會為每個可能出現的異常,定義一個異常類,當出現異常時,拋出該異常對象,catch塊對該異常對象進行捕獲。
示例代碼如下:
4.異常規范
我們看下面的兩行代碼
double hmean(int x,int y) throw(bad_thing)//可能拋出bad_thing異常
double hmean(int x,int y) throw()//不拋出異常
其中后面的throw()部分就是異常規范,指出該函數可能拋出的異常。
程序員來確定可能拋出的異常,這樣并不好。
在C++11中,已經摒棄了該規范。
5.棧解退
棧解退是很重要的概念。為什么這么說呢,當拋出異常后,程序終止,或被catch塊捕捉,我們必須要考慮內存的釋放問題。
我們先看一下,正常函數是如何處理內存釋放的。
函數調用時,調用函數的指令的地址會放到棧中,函數的參數或局部變量也將被添加到棧中或堆中。
如果在其中又調用了函數,則執行同樣的操作。
當函數結束以后,程序會跳到被調用時存儲的地址處,棧頂的元素被釋放,同時釋放其自動變量。
如果自動變量時類對象,則類的析構函數將被調用。
當函數出現異常時,程序也將不斷釋放棧,直到找到一個與該異常相對應的try塊的返回地址。
隨后,控制權將轉到塊尾的catch處理程序,而不是函數調用后面的第一條語句,這個過程稱為棧解退。
和正常函數調用不同的是,函數返回將處理該函數放在棧中的對象,而函數異常則處理,try塊和throw之間放在棧中的對象。
有了棧解退機制,引發異常后,也會釋放調用中間函數時棧中的對象。
我們看看下面的兩個例子:
void test1() {string mesg("hello");if(false)throw exception();return; }void test2() {double *ar = new double[n];if(false)throw exception();delete [] ar;return; }對于test1,函數異常后,會進行棧解退,string類析構函數會被調用,占用的內存將釋放。
對于test2,棧解退時,將刪除棧中變量ar,但ar指向的內存塊未釋放,并且不可訪問,會造成內存泄漏的問題。此時要如何處理呢?
可以在引發異常的代碼塊中,捕獲該異常,釋放該內存塊,然后重新引發異常。此時,內存塊就被釋放了。
6.關于catch塊
try {} catch(exception &ex) {}注意catch塊中參數為引用類型。當throw異常向上拋出時,該異常對象會被釋放,此時catch塊接收的異常對象為原始異常對象的一個副本。
使用引用的目的是,基類引用可以執行派生類對象。若不使用引用,則只能調用基類的特性。
7.C++標準異常庫
標準異常類exception在頭文件exception中定義,類含有一個名為what()的虛擬成員函數。從exception派生的類可以重新定義它。
C++庫定義了很多基于exception的異常類型,此處不再詳細介紹。
?
參考資料:《C++ Primer.Plus》 pp.616-642
總結
- 上一篇: javascript常用判断写法
- 下一篇: 从Script到Code Blocks、