契約斷言 (C++26 起)
契約斷言允許程式設計師指定程式狀態的屬性,這些屬性預計在執行期間的某些點保持有效。
目錄 |
[編輯] 解釋
契約斷言由函式契約說明符和contract_assert
語句引入。每個契約斷言都有一個謂詞,它是一個bool型別的表示式。
[編輯] 評估契約斷言
契約斷言的評估使用以下評估語義之一
評估語義 | 是檢查語義 | 是終止語義 |
---|---|---|
ignore | ||
observe | 是 | |
enforce | 是 | 是 |
quick-enforce | 是 | 是 |
對於契約斷言的任何給定評估,使用哪種評估語義是實現定義的。對於同一契約斷言的不同評估,包括常量評估期間的評估,評估語義可以不同。
如果使用“ignore”語義,則契約斷言的評估沒有效果。
如果使用檢查語義,則契約斷言的評估E
確定謂詞的值。是否評估謂詞是未指定的。如果滿足以下任何條件,則發生契約違規
存在一個可觀察的檢查點 CP
,它發生在E
之前,使得在A
之前發生的任何其他操作OP
也發生在CP
之前。
int num = 0; void f() pre((num++, false)); f(); // Increment of “num” might not occur, even if a checking semantic is used
[編輯] 處理契約違規
如果契約違規發生在顯然常量評估的上下文中
- 如果評估語義是“observe”,則會產生診斷。
- 如果評估語義是終止語義,則程式格式錯誤。
如果契約違規發生在非顯然常量評估的上下文中
- 如果評估語義是“quick-enforce”,則程式契約終止。
- 如果評估語義是“enforce”或“observe”,則呼叫契約違規處理器,並傳遞一個左值,該左值引用型別為const std::contracts::contract_violation的物件obj,該物件包含有關契約違規的資訊。
- obj的儲存以未指定的方式分配,但不會呼叫全域性分配函式。
- obj的生命週期在契約違規處理器的呼叫期間持續。
[編輯] 契約終止的程式
當程式契約終止時,它是實現定義的(取決於上下文)是
- 呼叫std::terminate,
- 呼叫std::abort,或
- 執行終止(不再發生執行步驟)。
[編輯] 契約違規處理器
程式的契約違規處理器是一個名為::handle_contract_violation的函式
void handle_contract_violation( std::contracts::contract_violation ); |
(C++26 起) (可選 noexcept) |
|
契約違規處理器的定義,稱為預設契約違規處理器,由實現提供(而不是標準庫標頭檔案)。
契約違規處理器是否可替換是實現定義的。如果契約違規處理器不可替換,則契約違規處理器的替換函式的宣告格式錯誤,無需診斷。
當契約違規處理器正常返回時
- 如果評估語義是“observe”,則控制流在契約斷言評估點之後正常繼續。
- 如果評估語義是“enforce”,則程式契約終止。
存在一個可觀察的檢查點 CP
,它發生在契約違規處理器正常返回之後,使得在契約違規處理器返回之後發生的任何其他操作OP
也發生在CP
之後。
[編輯] 處理斷言中的異常
如果契約違規發生是因為謂詞的評估透過異常退出,並且評估語義是“observe”或“enforce”,則契約違規處理器會在該異常的活動隱式處理程式中被呼叫。
當契約違規處理器正常返回時
- 如果評估語義是“observe”,則隱式處理程式不再被視為活動。
- 如果評估語義是“enforce”,則當契約終止發生時,隱式處理程式仍處於活動狀態。
可以使用std::current_exception()在契約違規處理器中檢查或重新丟擲當前異常。
[編輯] 按順序評估
要按順序評估契約斷言列表R
S
,使所有以下條件都得到滿足R
的所有元素都在S
中。R
的每個元素可以在S
中重複實現定義次數。- 如果契約斷言
A
在R
中先於另一個契約斷言B
,則A
的第一次出現先於B
的第一次出現在S
中。
void f(int i) { contract_assert(i > 0); // #1 contract_assert(i < 10); // #2 // valid sequence of evaluations: #1 #2 (no repeat) // valid sequence of evaluations: #1 #1 #2 #2 (repeat in sequence) // valid sequence of evaluations: #1 #2 #1 #2 (repeat alternatively) // valid sequence of evaluations: #1 #2 #2 #1 (second occurences can switch order) // invalid sequence of evaluations: #2 #1 (first occurences cannot switch) }
[編輯] 注意
可用評估語義的選擇範圍和靈活性取決於實現,並且不一定允許所有四種評估語義作為可能性。
在不同翻譯單元中為同一契約斷言選擇不同的評估語義可能導致單一定義規則的違規,當契約斷言具有副作用,改變常量表達式產生的值時
constexpr int f(int i) { contract_assert((++const_cast<int&>(i), true)); return i; } inline void g() { int a[f(1)]; // size dependent on the evaluation semantic of contract_assert above }
如果評估謂詞將產生的值是true,則不會發生契約違規,並且控制流在契約斷言評估點之後正常繼續。
如果謂詞的評估透過非區域性跳轉或終止程式退出,也不會發生契約違規。
C++ 標準建議預設契約違規處理器應產生適當格式化引數最相關內容的診斷輸出(對觀察到的契約斷言的潛在重複違規進行速率限制),然後正常返回。
功能測試宏 | 值 | 標準 | 特性 |
---|---|---|---|
__cpp_contracts |
202502L |
(C++26) | 契約 |
[編輯] 關鍵詞
[編輯] 另請參閱
contract_assert 語句 (C++26) |
在執行期間驗證內部條件 |
函式契約說明符 (C++26) | 指定前置條件 (pre) 和後置條件 (post) |