例外狀況規格 (throw, noexcept) (C++)
例外狀況規格是 C++ 語言功能,指出程式設計人員對於函式可傳播之例外狀況類型的意圖。 您可以使用例外 狀況規格來指定函式可能或可能不會結束例外狀況 。 編譯器可以使用這項資訊來優化對函式的呼叫,並在非預期的例外狀況逸出函式時終止程式。
在 C++17 之前,有兩種例外狀況規格。 noexcept 規格 是 C++11 的新功能。 它會指定是否可以逸出函式的潛在例外狀況集合是空的。 動態例外狀況規格 或 throw(optional_type_list)
規格在 C++11 中已被取代,並在 C++17 中移除,但 除外 throw()
,這是 的 noexcept(true)
別名。 此例外狀況規格的設計目的是提供哪些例外狀況可能從函式中擲回的摘要資訊,但在實務上卻發現有問題。 一個確實證明有點有用的動態例外狀況規格是無條件 throw()
的規格。 例如,函式宣告:
void MyFunction(int i) throw();
通知編譯器,函式不會擲回任何例外狀況。 不過,在模式中 /std:c++14
,如果函式擲回例外狀況,這可能會導致未定義的行為。 因此,我們建議使用 noexcept
運算子,而不是上述運算子:
void MyFunction(int i) noexcept;
下表摘要說明例外狀況規格的 Microsoft C++ 實作:
例外狀況規格 | 意義 |
---|---|
noexcept noexcept(true) throw() |
函式不會擲回例外狀況。 在 /std:c++14 模式中(這是預設值), noexcept 而且 noexcept(true) 是相等的。 從宣告 noexcept 或 noexcept(true) std::terminate 的函式擲回例外狀況時,會叫用 。 從宣告為 throw() 模式的 /std:c++14 函式擲回例外狀況時,結果是未定義的行為。 未叫用任何特定函式。 這是 C++14 標準的分歧,需要編譯器叫用 std::unexpected 。 Visual Studio 2017 15.5 版和更新版本 :在 模式中 /std:c++17 ,、 noexcept noexcept(true) 和 throw() 都相等。 在 模式中 /std:c++17 , throw() 是 的 noexcept(true) 別名。 在 /std:c++17 模式和更新版本中,當以任何這些規格宣告的函式擲回例外狀況時, std::terminate C++17 標準會視需要叫用。 |
noexcept(false) throw(...) 沒有規格 |
函式可以擲回任何類型的例外狀況。 |
throw(type) |
( C++14 和更早版本 ) 函式可以擲回 類型的例外狀況 type 。 編譯器接受 語法,但會將它解譯為 noexcept(false) 。 在 /std:c++17 模式和更新版本中,編譯器會發出警告 C5040。 |
如果在應用程式中使用例外狀況處理,呼叫堆疊中必須有一個函式來處理擲回的例外狀況,然後才結束標示 noexcept
為 、 noexcept(true)
或 throw()
的函式外部範圍。 如果擲回例外狀況的函式與處理例外狀況的函式之間呼叫的任何函式都會指定為 noexcept
、 noexcept(true)
(或 throw()
模式中 /std:c++17
),當 noexcept 函式傳播例外狀況時,程式就會終止。
函式的例外狀況行為取決於下列因素:
C 函式不允許明確例外狀況規格。 假設 C 函式不會在 下 /EHsc
擲回例外狀況,而且可能會在 、 /EHa
或 /EHac
下 /EHs
擲回結構化例外狀況。
下表摘要說明 C++ 函式是否可能會在各種編譯器例外狀況處理選項下擲回:
函式 | /EHsc |
/EHs |
/EHa |
/EHac |
---|---|---|---|---|
沒有例外狀況規格的 C++ 函式 | Yes | Yes | Yes | Yes |
具有 、 noexcept(true) 或 throw() 例外狀況規格的 noexcept C++ 函式 |
No | 否 | 是 | Yes |
具有 、 throw(...) 或 throw(type) 例外狀況規格的 noexcept(false) C++ 函式 |
Yes | Yes | Yes | Yes |
範例
// exception_specification.cpp
// compile with: /EHs
#include <stdio.h>
void handler() {
printf_s("in handler\n");
}
void f1(void) throw(int) {
printf_s("About to throw 1\n");
if (1)
throw 1;
}
void f5(void) throw() {
try {
f1();
}
catch(...) {
handler();
}
}
// invalid, doesn't handle the int exception thrown from f1()
// void f3(void) throw() {
// f1();
// }
void __declspec(nothrow) f2(void) {
try {
f1();
}
catch(int) {
handler();
}
}
// only valid if compiled without /EHc
// /EHc means assume extern "C" functions don't throw exceptions
extern "C" void f4(void);
void f4(void) {
f1();
}
int main() {
f2();
try {
f4();
}
catch(...) {
printf_s("Caught exception from f4\n");
}
f5();
}
About to throw 1
in handler
About to throw 1
Caught exception from f4
About to throw 1
in handler
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應