關鍵字throw將導致一系列事情的發生:
首先,它將建立程式所丟擲的物件的乙個拷貝。
然後,包含throw表示式的函式返回了這個物件,即使該函式原先並未設計為返回這種物件型別。
另外,異常發生之前建立的區域性物件被銷毀(呼叫物件的析構函式)。
乙個異常被丟擲以後,異常處理系統將按照在源**中出現的順序查詢最近的異常處理器。一旦找到匹配的異常處理器,就認為異常已經被處理了而不再繼續查詢下去。
最好是通過引用而不是通過值來捕獲異常。
當存在派生類時,首先捕獲派生類異常,並且將基類放到最後用於捕獲其他不太具體的異常。
捕獲所有型別的異常:
用省略號代替異常處理器的引數列表就可以實現:
catch(...)
最好將它放在異常處理器列表的最後。省略號異常處理器不允許接受任何引數,這種catch子句經常用於清理資源並重新丟擲所捕獲的異常。
在乙個異常處理器內部,使用不帶引數的throw語句可以重新丟擲異常,傳遞給位於更高一層語境中的異常處理器。
如果沒有任何乙個層次的異常處理器能夠捕獲某種異常,乙個特殊的庫函式terminate( )(在標頭檔案中)會被自動呼叫。預設情況下,terminate( )呼叫標準c庫函式abort( )使程式執行異常終止而退出。
在建構函式中分配資源時,如果在建構函式中發生異常,析構函式將沒有機會釋放這些資源,這個問題經常伴隨著「懸掛」指標出現,為了防止資源洩露,必須使用下列兩種方式之一來防止「不成熟的」資源分配方式:
1.在建構函式中捕獲異常,用於釋放資源。
2.在物件的建構函式中分配資源,並且在物件的析構函式中釋放資源。
為了實現第2種方式,可使用資源獲得式(resource acquisition is initialization,raii)技術,因為它使得物件對資源控制的時間與物件的宣告週期相等。(可利用模板來封裝指標,使得每個指標都被嵌入到物件中)。
由於在乙個典型的c++程式中動態分配記憶體是頻繁使用的資源,所以c++標準中提供了乙個raii封裝類(auto_ptr類),用於封裝指向分配的堆記憶體的指標,這就使程式能自動釋放建立物件時占用的堆記憶體。
exception類的定義在標頭檔案中。exception類的兩個主要派生類為logic_error和runtime_error,這兩個類的定義在標頭檔案中(這個標頭檔案包含)。logic_error和runtime_error都提供乙個引數型別為std::string的建構函式,這樣就可以將資訊儲存在這兩種型別的異常物件中,通過exception::what( )函式,可以從物件中得到它儲存的資訊。
最好從runtime_error類或logic_error 來派生自己的異常類,而不要直接從std::exception類派生,因為它並沒有提供乙個引數型別為std::string的建構函式。
void f( ); 意味著函式可能丟擲任何型別的異常。
void f( ) throw( ); 意味著函式不會丟擲任何異常。
異常規格說明:
預設的unexpected( )函式會呼叫terminate( )函式。
set_unexpected( )函式使用乙個函式指標作為引數,這個指標所指向的函式沒有引數,而且其返回值型別為void。
如果unexception處理器所丟擲的異常還是不符合函式的異常規格說明,下列兩種情況之一將會發生:
1.如果函式的異常規格說明中包括std::bad_exception,unexpected處理器所丟擲的異常會被替換成std::bad_exception物件,然後,程式恢復到這個函式被呼叫的位置重新開始異常匹配。
2.如果函式的異常規格說明中不包括std::bad_exception,程式會呼叫terminate( )函式。
可以在派生類函式的異常規格說明中指定較少的異常或指定為不丟擲異常。(在派生類函式中丟擲異常時只支援向下造型,不支援向上造型)
何時應該使用異常的最好建議是 :只有當函式不符合它的規格說明時才丟擲異常。
在以下情況不應該使用異常:
1.不要在非同步事件中使用異常。(異常依賴於程式執行棧上的動態函式呼叫鏈)
2.不要在處理簡單錯誤的時候使用異常。
3.不要將異常用於程式的流程控制。
4.不要強迫自己使用異常。
5.新異常,老**。
在下列情況下請使用異常:
1.修正錯誤並且重新除錯產生異常的函式。
2.在重新除錯中的函式外面補償一些行為以便使程式得以繼續執行。
3.在當前語境中做盡可能多的事情,並把同樣型別的異常重新丟擲到更高層的語境中。
4.在當前語境中做盡可能多的事情,並將乙個不同型別的異常丟擲到更高層的語境中。
5.終止程式。
6.將使用普通錯誤處理模式的函式(尤其是c庫函式)封裝起來,以便用異常來代替原有的錯誤處理模式。
7.簡化。如果建立的錯誤處理模式使事情變得更複雜並且難以使用,那麼異常可以使錯誤處理更加簡單有效得多。
8.使建立的庫和程式更安全。使用異常既是一種短期投資(為了除錯方便),也是一種長期投資(為了應用系統的健壯性)。
不要在析構函式內部觸發異常:
如果在析構函式中丟擲異常,這個新的異常可能會在現存的異常(其他異常)到達catch子句之前被丟擲,這會導致程式呼叫terminater( )函式。如果在析構函式中呼叫的函式可能會丟擲異常,應該在這個析構函式中編寫乙個try塊,並把這些函式呼叫放到try塊中,析構函式必須自己處理所有這些異常。絕對不能有任何乙個異常從析構函式中丟擲。
C 程式設計思想 卷二 防禦性程式設計
assert 巨集斷言定義在標頭檔案中 典型的assert 實現 ifdef ndebug define assert cond void 0 else void assertimpl const char const char long define assert cond cond void 0...
C 程式設計思想 卷二 通用演算法
判定函式 例 只把數值1中滿足條件的值複製到陣列2中 remove copy if 演算法對輸入序列的每個元素都應用gt15 並且在向輸出序列寫入時忽略掉那些使判定函式產生真值的元素。流迭代器 例 輸出流迭代器 例 輸入流迭代器 remove copy if 的第1個引數,把乙個istream it...
C 異常處理基本思想
傳統錯誤處理機制 通過函式返回值來處理錯誤。異常處理的基本思想 1 c 的異常處理機制使得異常的引發和異常的處理不必在同乙個函式中,這樣底層的函式可以著重解決具體問題,而不必過多的考慮異常的處理。上層呼叫者可以再適當的位置設計對不同型別異常的處理。2 異常是專門針對抽象程式設計中的一系列錯誤處理的,...