C 異常處理須知

2021-06-08 23:07:29 字數 3231 閱讀 2519

帖子內容: 

第一部分:

1. 異常發生時,異常物件會沿函式呼叫棧的反方向丟擲,這個過程常稱為棧展開(堆疊解退)。

2. 在棧展開過程中,如果異常物件始終都沒遇到可行的 catch 處理塊,系統將呼叫 terminate 函式強制終止程式。當然如果連 try 塊都沒有,系統將直接呼叫 terminate 函式。

3. 在棧展開過程中,編譯器保證適當的撤銷區域性物件。每個函式在棧展開退出時,它的區域性儲存會釋放,如果區域性物件是類型別,則自動呼叫物件的析構函式

4.析構函式應該從不丟擲異常,因為析構函式都是自動呼叫的,不會自動加上 try 測試塊,因此析構函式中異常的丟擲將直接導致系統呼叫 terminate 強制退出。在實踐中,由於析構函式釋放資源,不太可能出現異常,此外標準庫型別都保證它們的析構函式不會引發異常。

5. 如果在建構函式中發生異常,則該物件可能只是部分被構造,即使物件只是部分被構造,也要保證將會適當的撤銷已構造的成員。

6. 不能不處理異常,異常是足夠重要的,使程式不能按正常情況執行的正常事件。不去捕獲異常將直接導致程式的強制終止。

7. catch 子句接收的異常型別可以是內建型別,也可以是類型別,也就是說我們可以丟擲(throw)乙個如 int 的一般型別作為異常物件。

8. 如果 catch 子句只需了解異常的型別,則可以省去形參名,像這樣:catch(runtime_error) 來捕獲所有的異常,catch(...){} 經常與重新丟擲表示式結合使用,catch(...) 完成可做的所有區域性工作,然後重新丟擲異常。

20. 建構函式包括初始化列表的異常處理:

foo::foo(

intn)    

try:size(n), array(

newint

[n])    

catch

(const

bad_alloc& e)    

這裡的函式測試塊將初始化列表和函式體中的**都納入 try 塊中。

第二部分:

1. 標準異常類定義在四個標頭檔案中:exception,new,type_info,stdexcept。

2. exception 中定義了 exception 類,new 中定義了 bad_alloc 類,type_info 中定義了 bad_cast 類,stdexcept 中定義了 runtime_error、logic_error 類。

3. runtime_error 類(表示執行時才能檢測到的異常)包含了 overflow_error、underflow_error、range_error 幾個子類;logic_error 類(一般的邏輯異常)包含了 domain_error、invalid_argument、out_of_range、length_error 幾個子類;而所有的這些類都是 exception 類的子類。

4. exception、bad_alloc、bad_cast 類只定義了預設建構函式,無法在建立這些異常的時候提供附加資訊。其它異常類則只定義了乙個接受字串的建構函式,字串初始化式用於為所發生的異常提供更多的資訊。

5. 所有異常類都有乙個 what 虛函式,它返回乙個指向 c 風格字串的指標。

6. 應用程式可以從 exception 或者中間基類派生自已的異常類來擴充 exception 類層次。

7. 異常說明跟在函式形參表之後,乙個異常說明在關鍵字 throw 之後跟著乙個由圓括號括住的異常型別表(由逗號分隔),如:void foo(int) throw(bad_alloc, invalid_argument);。異常列表還可以為空:void foo(int) throw();,表示該函式不丟擲任何異常。

8. 異常說明有用的一種重要情況是,如果函式可以保證不會丟擲異常。確定函式將不丟擲任何異常,對函式的使用者和對編譯器都是非常有用的。知道函式不丟擲異常會簡化編寫該函式異常安全的**工作,而編譯器則可以執行被丟擲異常抑制的**優化。

9. 標準異常類中的析構函式和 what 虛函式都承諾不丟擲異常,如what的完整宣告為:virtual const char* what() const throw();。

10. 派生類中的虛函式不能丟擲基類虛函式中沒有宣告的新異常,這樣在編寫**時才有乙個可依賴的事實:基類中的異常列表是虛函式的派生類版本可以丟擲的異常列表的超集

11. 上半部分說過,在異常丟擲棧展開的時候,編譯器會適當撤銷函式退出前分配的區域性空間,如果區域性物件是類型別,則自動呼叫它的析構函式。但如果在函式內單獨地使用 new 動態的分配了記憶體,而且在釋放資源之前發生了異常,那麼棧展開時這個動態空間將不會被釋放。而由類型別物件分配的資源不管是靜態的還是動態的一般都會適當的被釋放,因為棧展開時保證呼叫它們的析構函式。因此,在可能存在異常的程式以及分配資源的程式最好使用類來管理那些資源,看乙個例子:

void

f()    

delete

p;    

}   

當這個異常發生時,p 指向的動態空間將不會被正常撤銷。現在我們用類來管理這個資源:

template

<

typename

t>    

class

resource    

resource(const

resource& r):size(r.size),data(

newt[r.size])    

resource& operator=(const

resource& r)    

return

*this

;    

}    

~resource()     

t operator(unsigned int

index);    

const

t operator(unsigned 

intindex) 

const

;    

};    

void

f()    

}   

這裡即使丟擲了異常,也會自動呼叫物件 p 的析構函式。

12. 異常丟擲棧展開的時候,編譯器對區域性類物件析構函式的自動執行導致了乙個重要的程式設計技巧的出現,它使程式更為異常安全的。通過定義乙個類來封裝資源的分配和釋放,可以保證正確的釋放資源。這一技術常稱為「資源分配即初始化」,簡稱為 raii。第 11 條已給出了它的用法。

更多參考:

C 異常處理須知

帖子內容 第一部分 1.異常發生時,異常物件會沿函式呼叫棧的反方向丟擲,這個過程常稱為棧展開 堆疊解退 2.在棧展開過程中,如果異常物件始終都沒遇到可行的 catch 處理塊,系統將呼叫 terminate 函式強制終止程式。當然如果連 try 塊都沒有,系統將直接呼叫 terminate 函式。3...

C 異常處理須知

第一部分 1.異常發生時,異常物件會沿函式呼叫棧的反方向丟擲,這個過程常稱為棧展開。2.在棧展開過程中,如果異常物件始終都沒遇到可行的catch處理塊,系統將呼叫terminate函式強制終止程式。當然如果連try塊都沒有,系統將直接呼叫terminate函式。3.在棧展開過程中,編譯器保證適當的撤...

C 異常使用須知

本文翻譯自 相比錯誤 異常為錯誤處理提供了很多便利。這些好處包括 儘管有這些好處,然而大部分人仍然介懷異常的額外開銷而不願意使用。基於異常的實現機制,額外開銷來自兩方面 時間開銷 增加執行時間 和空間開銷 增加可執行檔案和記憶體消耗 在這二者之中,時間開銷更被關注。然而,對於乙個良好的c 異常實現,...