17.1 異常處理
使用異常處理,程序中獨立開發的各部分能夠就程序執行期間出現的問題相互通信,並處理這些問題。程序的一個部分能夠檢測出本部分無法解決的問題,這個問題檢測部分可以將問題傳遞給准備處理問題的其他部分。
通過異常我們能夠將問題的檢測和問題的解決分離,這樣程序的問題檢測部分可以不必了解如何處理問題。
17.1.1 拋出類類型的異常
異常是通過拋出(throw)對象而引發(raise)的。該對象的類型決定應該激活哪個處理代碼。被選中的處理代碼是調用鏈中與該對象類型匹配且離拋出異常位置最近的那個。
異常以類似於將實參傳遞給函數的方式拋出和捕獲。異常可以是可傳給非引用形參的任意類型的對象,這意味著必須能夠復制該類型的對象。
執行throw的時候,不會執行跟在throw後面的語句,而是將控制從throw轉移到匹配的catch,該catch可以是同一函數中局部的catch,也可以在直接或間接調用發生異常的函數的另一個函數中。控制從一個地方傳遞到另一個地方,這有兩個重要含義:
(1)沿著調用鏈的函數提早退出。
(2)一般而言,在處理異常的時候,拋出異常的塊中的局部存儲不存在了。
因為在處理異常的時候會釋放局部存儲,所以被拋出的對象就不能再局部存儲,而是用throw表達式初始化一個稱為異常對象(exception object)的特殊對象。這個對象由throw創建,並被初始化為被拋出的表達式的副本。異常對象將傳給對應的catch,並且在完全處理了異常之後撤銷。
異常對象通過復制被拋出表達式的結果創建,該結果必須是可以復制的類型。
1. 異常對象與繼承
當拋出一個表達式的時候,被拋出對象的靜態編譯時類型將決定異常對象的類型。
2. 異常與指針
用拋出表達式拋出靜態類型時,比較麻煩的一種情況是,在拋出中對指針解引用。對指針解引用的結果是一個對象,其類型與指針的類型匹配。如果指針指向繼承層次中的一種類型,指針所指對象的類型就有可能與指針的類型不同。無論對象的實際類型是什麼,異常對象的類型都與指針的靜態類型相匹配。如果該指針是一個指向派生類對象的基類類型指針,則那個對象將被分割,只拋出基類部分。
拋出指向局部對象的指針總是錯誤的,其理由由與函數返回指向局部對象的指針是錯誤的一樣。拋出指針的時候,必須確定進入處理代碼時指針所指向的對象存在。
如果拋出指向局部對象的指針,而且處理代碼在另一函數中,則執行處理代碼時指針所指向的對象將不再存在。即使處理代碼在同一函數中,也必須確信指針所指向的對象在catch處存在。如果指針指向某個在catch之前退出的塊中的對象,那麼,將在catch之前撤銷該局部對象。
拋出指針通常是個壞主意:拋出指針要求在對應處理代碼存在的任意地方存在指針所指向的對象。
void Method1(){
try
{
throw range_error("error~");
}
catch(exception &e)
{
cout<<e.what()<<endl;
}
}
void Method1(){
try
{
throw range_error("error~");
}
catch(exception &e)
{
cout<<e.what()<<endl;
}
}Method1(); //error~
摘自 xufei96的專欄