錯誤和例外處理 (現代的 C++)
在現今 C++,在大部分的情況下,是使用例外狀況的較佳的方式來報告和處理邏輯錯誤和執行階段錯誤。特別是當堆疊可能包含數個函式呼叫之間偵測到錯誤時的函式、 函式具有要知道如何處理它的內容。例外狀況會偵測到傳遞的呼叫堆疊資訊錯誤的程式碼提供一個正式且完整定義的方法。
程式錯誤通常會分成兩大類: 邏輯錯誤所造成的程式設計錯誤,比方說,「 索引超出範圍 」 錯誤,並且執行階段錯誤的程式控制範圍內的程式設計師而言,比方說,「 網路服務無法使用 」 的錯誤。在 c 樣式的程式設計和 COM,錯誤報告被管理傳回的值,表示錯誤碼或錯誤狀態碼為特定的函式,或藉由設定呼叫者可以選擇性地擷取每個函式呼叫,以查看是否已報告錯誤之後的全域變數。比方說,COM 程式設計使用 HRESULT 傳回值,來傳達錯誤給呼叫者,且 Win32 API 時發生函式來擷取呼叫堆疊所報告的是最後一個錯誤。在這兩種情況下,完全由呼叫者識別程式碼並進行適當地回應。如果呼叫端並不會明確地處理錯誤的程式碼,程式可能不會發出警告,當機,或繼續執行不正確的資料,並產生不正確的結果。
現代的 C++ 偏好的例外狀況,原因如下:
例外狀況會強制辨識錯誤狀況,並處理呼叫的程式碼。未處理的例外狀況會停止執行程式。
例外狀況會跳至可處理此錯誤的呼叫堆疊中的點。中繼函數可以讓傳播例外狀況。它們並沒有與其他圖層協調。
之後會發生例外狀況,例外狀況堆疊回溯機制會終結妥善定義的規則的範圍內的所有物件。
例外狀況可讓您清楚劃分所偵測到錯誤時的程式碼,並處理錯誤的程式碼。
下面的簡單的範例示範擲回和攔截例外狀況,在 C++ 的必要語法。
#include <stdexcept>
#include <limits>
#include <iostream>
using namespace std;
class MyClass
{
public:
void MyFunc(char c)
{
if(c < numeric_limits<char>::max())
throw invalid_argument("MyFunc argument too large.");
//...
}
};
int main()
{
try
{
MyFunc(256); //oops!
}
catch(invalid_argument& e)
{
cerr << e.what() << endl;
return -1;
}
//...
return 0;
}
在 C++ 例外狀況如語言 C# 及 JAVA 中所示。在try封鎖,如果有一個例外是擲回 ,才可攔截到的第一個相關聯catch與型別相符的例外狀況區塊。也就是說,執行會跳從throw陳述式,以catch陳述式。如果找不到沒有可用的 catch 區塊, std::terminate叫用時,程式便會結束。在 C++ 中,可能會擲回任何型別 ; 不過,我們建議您擲回的型別,是直接或間接衍生自std::exception。在前一個範例中,例外狀況類型而定, invalid_argument,定義在標準程式庫 <stdexcept> 標頭檔。C + + 不提供,而且不需要, finally區塊,並確定在擲回例外狀況時,會釋放所有的資源。資源擷取已初始化 (RAII) 方法,使用智慧型指標,提供的資源清除所需的功能。如需詳細資訊,請參閱 How to: 設計例外狀況的安全。C + + 堆疊回溯機制的相關資訊,請參閱例外狀況和堆疊回溯 C++ 中。
基本的指導方針
健全的錯誤處理是一大挑戰,任何程式設計語言。雖然例外狀況提供許多功能,可支援很好的錯誤處理,但它們無法執行所有工作,讓您。若要了解例外狀況機制的好處,記住例外狀況在設計您的程式碼。
使用判斷提示來檢查應該永遠不會發生的錯誤。若要檢查有可能發生的錯誤,比方說,參數的公用函數的輸入驗證錯誤,使用例外狀況。如需詳細資訊,請參閱 Exceptions VS. Assertions。
處理錯誤的程式碼可能會偵測到錯誤時的程式碼從隔開一或多個中間的函式呼叫時,請使用例外狀況。請考慮是否要改用錯誤碼在效能關鍵的迴圈時處理錯誤的程式碼會偵測到該程式碼緊密結合。如需何時不使用例外狀況詳細資訊,請參閱When Not to Use Exceptions。
每個函式,可能會擲回,或傳播例外狀況,提供三種例外狀況的保證: 強式的保證、 基本保證回應時間、 或 nothrow (noexcept) 的保證。如需詳細資訊,請參閱 How to: 設計例外狀況的安全。
擲回例外狀況傳值方式、 攔截它們的參考。您不會攔截您無法處理。如需詳細資訊,請參閱 擲回和攔截例外狀況 (C++) 的方針。
請勿使用例外狀況規格,都已被取代的 C++ 11。如需詳細資訊,請參閱 Exception specifications and noexcept。
當套用時,請使用標準程式庫例外狀況型別。衍生自訂例外狀況型別,從例外狀況類別階層架構。如需詳細資訊,請參閱 How to: 使用標準的程式庫的例外狀況物件。
不用讓手指逃出地解構函式或記憶體解除配置的函式的例外狀況。
例外狀況和效能
例外狀況機制會具有變得很小的效能成本在擲回任何例外狀況。如果擲回例外狀況時,堆疊橫越的成本及回溯是大致上可以比較函式呼叫的成本。附加的資料結構所需來追蹤呼叫堆疊之後, try區塊,並在擲回例外狀況時回溯堆疊所需的其他指示。不過,在大部分的情況下,在效能和記憶體耗用量的成本並不重要。例外狀況,對效能產生負面的影響很可能是重大只在非常的記憶體有限的系統中,或在效能關鍵迴圈錯誤很可能會定期發生,並處理它的程式碼會報告它的程式碼有著緊密的結合。在任何情況下,就無法得知實際成本的例外狀況,而不需要程式碼剖析和測量。即使是在這些特別的情況下時的成本是有意義的您可以權衡其對抗提高的正確性、 更簡單的可維護性和其他優點,包括所提供的設計完善的例外狀況原則。
例外狀況 VS.的判斷提示
例外狀況和判斷提示是這兩個不同的機制,來偵測在程式中的執行階段錯誤。使用判斷提示就絕不會則為 true,如果您的程式碼是正確的開發期間測試條件。沒有在使用例外狀況,因為這項錯誤表示程式碼中的項目已固定,來處理這類錯誤點,並不代表該程式必須在執行階段從復原的條件。判斷提示會停止執行的陳述式,讓您可以檢查程式狀態中偵錯工具。 例外狀況會繼續執行,從第一個適當的 catch 處理常式。使用例外狀況,以檢查錯誤的情況可能發生在執行階段中,即使您的程式碼正確,比方說,「 找不到檔案 」 或 「 超出記憶體 」。您可以復原這些條件,即使在復原只是將輸出訊息至記錄檔,並且結束程式。一定要檢查公用函式的引數使用的例外狀況。即使您的函式為無錯誤,您可能沒有使用者可能會傳遞給它的引數的完整控制權。
與 Windows SEH 例外的 C++ 例外狀況
C 與 C++ 程式可以使用結構化的例外處理 (SEH) 機制,在 Windows 作業系統中。在 SEH 的概念類似於 C++ 例外中的不同之處在於 SEH 使用__try, __except,以及__finally而不是建構try和catch。在 Visual C++ 中,C++ 例外狀況被執行 SEH。然而,當您撰寫 C++ 程式碼時,使用 C++ 例外狀況的語法。
如需 SEH 的詳細資訊,請參閱 結構化的例外處理 (C++)。
例外狀況規格和 noexcept
例外狀況規格所導入 C++ 中,用來指定函式可能會擲回的例外狀況。不過,例外狀況規格證明在練習中,有問題,而且已取代在 C + + 11 草稿標準。我們建議您不要使用例外狀況規格除了throw(),表示例外狀況允許任何逸出的例外狀況。如果您必須使用型別的例外狀況規格throw(型別),請注意, Visual C++離開標準以特定的方式。如需詳細資訊,請參閱 例外狀況規格。noexcept規範會介紹在 C + + 中做為慣用的替代方案的 11 throw()。