異常處理

例外處理對應的處理，這種情況經常會破壞程式正常的流程。它通常由特殊的程式語言結構、計算機硬體機制所構成的。具體實現由硬體和軟體自身定義而決定。一些例外，尤其是硬體，將會在被中斷後進行恢復。硬體領域.硬體的異常處理機制由 CPU 完成。這種機制支援錯誤檢測，在發生錯誤後會將程式流跳轉到專門的錯誤處理過程中。發生異常前的狀態儲存在棧上。作業系統提供的例外處理設施.針對程式中可能發生的例外，作業系統可能透過 IPC 來提供對應的處理設施。程序執行過程中發生的中斷通常由操作提供的「中斷服務子程式」處理，作業系統可以藉此向該程序傳送訊號。程序可以透過註冊訊號處理器的方式自行處理訊號，也可以讓作業系統執行預設行為。從程序的視角，硬體中斷相當於可恢復異常，雖然中斷一般與程式流本身無關。軟體領域.在程式語言領域，通常 例外，並執行處理。從子程式routine作者的角度看，如果要表示當前子程式無法正常執行，丟擲例外是很好的選擇。無法正常執行的原因可以是輸入引數無效等等。在不支援例外的系統中，子程式需要透過返回特殊的實作類似的功能。然而回傳錯誤碼可能導致，子程式的使用方需要編寫額外的程式碼，才能將普通的回傳值與錯誤碼相區別。程式語言對異常有著截然不同的定義，但現代語言大致上可分兩類：Kiniry 強調“語言的設計僅僅部分地影響了例外機制的使用，結果上，。另外，其他主要的影響還有示例、核心程式碼的編寫、技術書籍雜誌文章以及相關討論”。歷史.在1960和1970年代，Lisp語言發展出軟體例外。最初版本是在1962年 Lisp 1.5的時候，這時候異常透過codice_1關鍵詞進行捕捉，並在出錯時候，透過codice_2進行回傳，而不是以前的終止程式或者進行偵錯程式。1960年代後半，MacLisp語言透過codice_3關鍵詞引入引發，對應著現今常見的codice_9。該操作也被 Common Lisp使用了。與之同時代，Scheme也誕生了codice_10，用於處理closures中的異常。#重定向 and #重定向 是首篇文章介紹結構化的異常處理。 1980年後，異常處理被廣泛利用於許多程式語言。PL/I語言使用的是動態域。雖然現在的一些程式語言支援不含錯誤資訊的例外，但是他們並不常見。一開始，軟體的例外處理是包含恢復的例外：恢復語法，因此恢復語句就很少再出現了，通常只能在類似Common Lisp和Dylan這種語言中見到。爭論.1980年Tony Hoare 在異常處理上提出了反對意見，這樣描述Ada語言時，認為異常處理是十分危險的。對於軟體而言，異常處理經常無法正確的處理，尤其是當這裡有多種來自不同原始碼的異常時。在對五百萬行Java程式碼進行資料流分析時，我們發現了超過1300個異常處理。這是1999-2004年的前沿報告以及他們的結論，Weimer 和 Necula寫到，異常是一個十分嚴峻的問題，他們會創造隱藏的控制流途徑，這種途徑是程式設計人員很難去推理的。Go語言的初始版本並沒有異常處理，而因此被有的開發者認為控制流十分冗餘。後來，追加了類似的異常處理的語法/機制，但是Go語言的作者建立這僅僅在整個程式不可恢復的錯誤時候使用它。異常，作為一個非結構化的流程，它會增加資源洩露的可能性，會在這段程式碼的控制權結束時自動釋放資源。錯誤處理.錯誤處理是透過處理函式的返回值的形式從而處理錯誤的一種程式設計方式。在Go等返回值可為複數的語言中，可透過將其中一個值設為錯誤值，從而達到錯誤處理的效果。f, err := os.Open("filename.ext")if err != nil {log.Fatal(err)// do something with the open *File f在僅僅支援返回狀態碼的語言裡，可透過處理錯誤碼，達到錯誤處理的效果。shell語言可透過codice_12獲得函式執行的退出碼，從而判斷是否出錯。在其他語言中，可以透過判斷結果的某一個特徵，從而達到錯誤處理部分的效果，但不意味著這些語言自身支援錯誤處理。如，Java等面向物件的語言往往會透過null值判斷是否執行失敗，但有時候也會透過異常處理判斷是否執行失敗。未捕捉異常.如果一個異常丟擲後，沒有被捕捉，那麼未捕捉異常將會在執行時被處理。進行該處理的程式。值得了解的是，在即便未捕捉異常導致了程式異常中斷能正常地執行，因為 執行時 控制著整個程式的執行。作為預設的未捕捉異常處理器是可以被替換的，不管是全域性還是單執行緒的，新的未捕捉異常處理器可以嘗試做這些事情：未捕捉異常導致關閉了的執行緒，使之重啟；提供另一種方式記錄日誌；讓使用者報告未捕捉異常等等。在Java中，單一執行緒可以使用codice_13 ，全域性可以用codice_14；在python中，可透過修改codice_15。異常的靜態檢查.檢查性異常.Java的設計者設計了 檢查性異常。程式語言相關支援.許多常見的程式設計語言，包括Actionscript，Ada，BlitzMax，C++，C#，D，ECMAScript，Eiffel，Java，ML，Object Pascal。多數語言的異常機制的語法是類似的：用codice_22或codice_23丟擲一個異常物件標示其結束；可連續出現若干個異常處理子句，每個處理特定型別的異常。某些語言允許codice_27子句，用於無異常出現的情況。更多見的是codice_28子句，無論是否出現異常它都將執行，用於釋放異常處理所需的一些資源。C++異常處理是資源獲取即初始化的基礎。C語言一般認為是不支援異常處理的。Perl語言可選擇支援結構化異常處理。Python語言對異常處理機制是非常普遍深入的，所以想寫出不含codice_29的程式非常困難。Python.在python裡只存在異常與語法錯誤。語法錯誤是在執行之前發生的。而異常是在執行時發生的錯誤，它將無條件停止程式，除非進行捕捉處理。Java.異常是異常事件。codice_30 和codice_31均是不檢查的異常(Unchecked Exceptions)。錯誤不等於錯誤類，錯誤類代表著不應該被捕捉的嚴重的問題。codice_30 意味著程式出現問題了。Go.Go語言提倡的是錯誤處理。Go語言設計者系統希望使用者在錯誤出時，顯式地檢查錯誤。 Go雖然不提供與Java語言的codice_34同等的功能語句，但是取而代之，提供了輕型的異常處理機制codice_35。異常安全.一段程式碼是異常安全的，如果這段程式碼執行時的失敗不會產生有害後果，如記憶體洩露、儲存資料混淆、或無效的輸出。異常安全可分成不同層次：例如，考慮一個smart vector型別，如C++的 codice_36或Java的 codice_37。當一個數據項codice_38插入vector codice_39，必須實際增加codice_38的值到vector的內部物件列表中並且修改vector的計數域以正確表示codice_39中儲存了多少資料項；此時如果已有的儲存空間不夠大，就需要分配新的記憶體。記憶體分配可能會失敗並丟擲異常。因此，vector資料型別如果是“失敗透明”保證將會非常困難甚至不可能實現。但vector型別提供“強異常安全”保證卻是相當容易的；在這種情況下，codice_38插入codice_39或者成功，或者codice_39保持不變。如果vector型別僅提供“基本異常安全”保證，如果資料插入失敗，codice_39可能包含也可能不包含codice_38的值，但至少codice_39的內部表示是一致的。但如果vector資料型別是“最小異常安全”保證，codice_39可能會是無效的，例如codice_39的計數域被增加了，但codice_38並未實際插入，使得內部狀態不一致。對於“異常不安全”的實現，程式可能會崩潰，例如寫入資料到無效的記憶體。通常至少需要基本異常安全。失敗透明是難於實現的，特別是在編寫庫函式時，因為對應用程式的複雜知識缺少獲知。