命名空間
變體
動作

合約斷言 (自 C++26 起)

出自 cppreference.com
< cpp‎ | language
 
 
C++ 語言
一般主題
流程控制
條件執行陳述式
if
疊代陳述式 (迴圈)
for
範圍 for (C++11)
跳躍陳述式
函式
函式宣告
Lambda 函式運算式
inline 指定符
動態例外規範 (直到 C++17*)
noexcept 指定符 (C++11)
例外
命名空間
型別
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期指定符
初始化
 
 

合約斷言允許程式設計師指定程式在執行過程中,於特定點預期應成立的狀態屬性。

目錄

[編輯] 說明

合約斷言函式合約限定符contract_assert 陳述式引入。每個合約斷言都有一個謂詞 (predicate),它是一個型別為 bool 的運算式。

[編輯] 評估合約斷言

合約斷言的評估會使用以下其中一種評估語義:

 評估語義   是否為檢查語義   是否為終止語義 
ignore
observe (觀察)
enforce (強制執行)
quick-enforce (快速強制執行)

對於任何給定的合約斷言評估,使用哪種評估語義是由實作定義的。對於同一合約斷言的不同評估,評估語義可能有所不同,包含常數評估期間的評估。

若使用「ignore (忽略)」語義,合約斷言的評估不產生任何效果。

若使用檢查語義,合約斷言的評估 E 會確定謂詞的值。謂詞是否被評估是不明確的。如果滿足以下任一條件,則會發生合約違規

存在一個發生在 E 之前的可觀察檢查點 (observable checkpoint) CP,使得任何其他發生在 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」,則會產生診斷訊息。
  • 若評估語義為終止語義,則程式格式錯誤 (ill-formed)。

如果合約違規發生在非明確常數評估的環境中:

  • 若評估語義為「quick-enforce」,程式將被合約終止。
  • 若評估語義為「enforce」或「observe」,合約違規處理常式將被呼叫,並傳入一個參照至型別為 const std::contracts::contract_violation 之物件 obj 的左值,該物件包含有關合約違規的資訊。
    • obj 的儲存空間以未指定的方式分配,但不會呼叫任何全域分配函式
    • obj 的生命週期持續到合約違規處理常式呼叫結束為止。

[編輯] 合約終止程式

當程式被合約終止時,(視環境而定)是否發生以下情況是由實作定義的:

[編輯] 合約違規處理常式

程式的合約違規處理常式是一個名為 ::handle_contract_violation 的函式:

void handle_contract_violation( std::contracts::contract_violation );
(C++26 起)
(可選擇性加上 noexcept)

合約違規處理常式的定義,稱為預設合約違規處理常式,由實作(而非標準函式庫標頭檔)提供。

合約違規處理常式是否可以替換是由實作定義的。如果合約違規處理常式不可替換,則宣告一個替換函式是不合法的,且不需要診斷。

當合約違規處理常式正常返回時:

  • 若評估語義為「observe」,控制流程在合約斷言評估點之後正常繼續。
  • 若評估語義為「enforce」,程式將被合約終止。

存在一個發生在合約違規處理常式正常返回之後的可觀察檢查點 CP,使得任何其他在處理常式返回之後發生的作業 OP,也都發生在 CP 之後。

[編輯] 處理來自斷言的例外

如果合約違規是因為謂詞評估因例外而退出,且評估語義為「observe」或「enforce」,則合約違規處理常式會從該例外的隱式處理常式 (handler) 內被呼叫。

當合約違規處理常式正常返回時:

  • 若評估語義為「observe」,該隱式處理常式將不再被視為活躍。
  • 若評估語義為「enforce」,當合約終止發生時,該隱式處理常式仍保持活躍。

當前的例外可以在合約違規處理常式內,使用 std::current_exception() 進行檢查或重新拋出。

[編輯] 按順序評估

若要按順序評估合約斷言列表 R

1) 建構一個合約斷言列表 S,使得滿足以下所有條件:
  • R 的所有元素都在 S 中。
  • R 中的每個元素在 S 中可重複出現實作定義的次數。
  • 如果合約斷言 AR 中位於合約斷言 B 之前,則 A 的第一次出現必須在 S 中位於 B 的第一次出現之前。
2) 評估 S 中的每個元素,使得如果合約斷言 AS 中位於合約斷言 B 之前,則 A 的評估定序於 (sequenced before) B 的評估之前。
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)
}

[編輯] 附註

可用的評估語義選擇之範圍與靈活性取決於實作,且不必允許所有四種評估語義作為選項。

當合約斷言具有會改變常數運算式產生的值之副作用時,若在不同的轉譯單元中為相同的合約斷言選擇了不同的評估語義,可能會導致違規單一定義規則 (ODR)

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,則不會發生合約違規,且控制流程在合約斷言評估點之後正常繼續。

如果謂詞的評估是通過非局部跳轉 (non-local jumps) 或終止程式而退出,也不會發生合約違規。

C++ 標準建議,預設合約違規處理常式應產生診斷輸出,適當地格式化參數中最相關的內容(針對重複出現的觀察合約違規進行頻率限制),然後正常返回。

特性測試巨集 數值 標準 功能
__cpp_contracts 202502L (C++26) 合約

[編輯] 關鍵字

contract_assert, pre, post

[編輯] 參見

contract_assert 陳述式 (C++26) 在執行過程中驗證內部條件[編輯]
函式合約限定符 (C++26) 指定前置條件 (pre) 與後置條件 (post)[編輯]
English Deutsch 日本語 中文(简体) 中文(繁體)