17.1.2 棧展開
如果對拋出異常的函數的調用是在try塊中,則檢查與該try相關的catch子句。如果找到匹配的catch,就處理異常;如果找不到匹配的catch,調用函數也退出,並且繼續在調用這個函數的函數中查找。這個過程,稱之為棧展開(stack unwinding)。
1. 為局部對象調用析構函數
棧展開期間,釋放局部對象所用的內存並運行類類型局部對象的析構函數。
2. 析構函數應該從不拋出異常
在為某個異常進行棧展開的時候,析構函數如果又拋出自己的未經處理的另一個異常,將會掉值調用標准庫的terminate函數。一般而言,terminate函數將調用abort函數,強制從整個程序非正常退出。
3. 異常與構造函數
與析構函數不同,構造函數內部所做的事情經常會拋出異常。如果在構造函數對象的時候發生異常,則該對象可能只是部分被構造,它的一些成員可能已經初始化,而另一些成員在異常發生之前還沒有初始化。即使對象只是部分被構造了,也要保證將會適當地撤銷已構造的成員。
4. 未捕獲的異常終止程序
如果找不到匹配的catch,程序就調用庫函數terminate。
17.1.3 捕獲異常
catch子句(catch clause)中的異常說明符(exception specifier)看起來像只包含一個形參的形參表,異常說明符是在其後跟一個(可選)形參名的類型名。
說明符的類型據诶的那個可處理代碼能夠捕獲的異常種類。種類必須是完全類型,即必須是內置類型或者是已經定義的程序員自定義類型。類型的前向聲明不行。
1. 查找匹配的處理代碼
在查找匹配的catch期間,找到的catch不必是與異常最匹配的那個catch,相反,將選中第一個找到的可以處理該異常的catch。因此在catch子句列表中,最特殊的catch必須最先出現。
允許從非const到const的轉換。
允許從派生類型到基類類型的轉換。
將數組轉換為指向數組類型的指針,將函數轉換為指向函數類型的適當指針。
2. 異常說明符
進入catch的時候,用異常對象初始化catch的形參。像函數形參一樣,異常說明符類型可以是引用。異常對象本身是被拋出對象的副本。是否再次將異常對象復制到catch位置取決於異常說明符類型。
如果說明符不是引用,就將異常對象復制到catch形參中,catch操作異常對象的副本,對形參所做的任何改變都只作用域副本,不會作用於異常對象本身。如果說明符是引用,則像引用形參一樣,不存在單獨的catch對象,catch形參只是異常對象的另一名字。對catch形參所做的改變作用於異常對象。
3. 異常說明符與繼承
像形參聲明一樣,基類的異常說明符可以用於捕獲派生類型的異常對象,而且,異常說明符的靜態類型決定catch子句可以執行的動作。如果被拋出的異常對象是派生類類型的,但由接受基類類型的catch處理,那麼,catch不能使用派生類特有的任何成員。
通常,如果catch子句處理因繼承而相關的類型的異常,它就應該將自己的形參定義為引用。
4. catch子句的次序必須反映類型層次
將異常類型組織成類層次的時候,用戶可以選擇應用程序處理異常的粒度級別。
因為catch子句按出現次序匹配,所以使用來自繼承層次的程序必須將它們的catch子句排序,以便派生類型的處理代碼出現在其基類類型的catch之前。
帶有因繼承而相關的類型的多個catch子句,必須從最低派生類型到最高派生類型排序。