例外狀況規格是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++實作:
| 例外狀況規格 | 意義 |
|---|---|
noexceptnoexcept(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擲回例外狀況,而且可能會在、 /EHs或 /EHa下/EHac擲回結構化例外狀況。
下表摘要說明C++函式是否可能會在各種編譯程式例外狀況處理選項下擲回:
| 函式 | /EHsc |
/EHs |
/EHa |
/EHac |
|---|---|---|---|---|
| 沒有例外狀況規格的 C++ 函式 | Yes | Yes | Yes | Yes |
使用、 noexcept或 noexcept(true) 例外狀況規格C++函throw()式 |
No | No | Yes | Yes |
使用、 noexcept(false)或 throw(...) 例外狀況規格C++函throw(type)式 |
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