c++異常處理

異常,讓一個函數可以在發現自己無法處理的錯誤時拋出一個異常,希望它的調用者可以直接或者間接處理這個問題。而傳統錯誤處理技術,檢查到一個局部無法處理的問題時:

1.終止程序(例如atol,atoi,輸入NULL,會產生段錯誤,導致程序異常退出,如果沒有core文件,找問題的人一定會發瘋)

2.返回一個表示錯誤的值(很多系統函數都是這樣,例如malloc,內存不足,分配失敗,返回NULL指針)

3.返回一個合法值,讓程序處於某種非法的狀態(最坑爹的東西,有些第三方庫真會這樣)

4.調用一個預先準備好在出現"錯誤"的情況下用的函數。

第一種情況是不允許的,無條件終止程序的庫無法運用到不能當機的程序裏。第二種情況,比較常用,但是有時不合適,例如返回錯誤碼是int,每個調用都要檢查錯誤值,極不方便,也容易讓程序規模加倍(但是要精確控制邏輯,我覺得這種方式不錯)。第三種情況,很容易誤導調用者,萬一調用者沒有去檢查全局變量errno或者通過其他方式檢查錯誤,那是一個災難,而且這種方式在併發的情況下不能很好工作。至於第四種情況,本人覺得比較少用,而且回調的代碼不該多出現。

使用異常,就把錯誤和處理分開來,由庫函數拋出異常,由調用者捕獲這個異常,調用者就可以知道程序函數庫調用出現錯誤了,並去處理,而是否終止程序就把握在調用者手裏了。

但是,錯誤的處理依然是一件很困難的事情,C++的異常機制爲程序員提供了一種處理錯誤的方式,使程序員可以更自然的方式處理錯誤。

異常的描述

函數和函數可能拋出的異常集合作爲函數聲明的一部分是有價值的,例如

void f(int a) throw (x2,x3);

表示f()只能拋出兩個異常x2,x3,以及這些類型派生的異常,但不會拋出其他異常。如果f函數違反了這個規定,拋出了x2,x3之外的異常,例如x4,那麼當函數f拋出x4異常時,
會轉換爲一個std::unexpected()調用,默認是調用std::terminate(),通常是調用abort()。

如果函數不帶異常描述,那麼假定他可能拋出任何異常。例如:

int f();  //可能拋出任何異常

不帶任何異常的函數可以用空表表示:

int g() throw (); // 不會拋出任何異常

捕獲異常

捕獲異常的代碼一般如下:

try {
    throw E();
}
catch (H h) {
     //何時我們可以能到這裏呢
}

1.如果H和E是相同的類型

2.如果H是E的基類

3.如果H和E都是指針類型,而且1或者2對它們所引用的類型成立

4.如果H和E都是引用類型,而且1或者2對H所引用的類型成立

從原則上來說,異常在拋出時被複制,我們最後捕獲的異常只是原始異常的一個副本,所以我們不應該拋出一個不允許拋出一個不允許複製的異常。

此外,我們可以在用於捕獲異常的類型加上const,就像我們可以給函數加上const一樣,限制我們,不能去修改捕捉到的那個異常。

還有,捕獲異常時如果H和E不是引用類型或者指針類型,而且H是E的基類,那麼h對象其實就是H h = E(),最後捕獲的異常對象h會丟失E的附加攜帶信息。

 

發佈了24 篇原創文章 · 獲贊 4 · 訪問量 9032
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章