名前空間
変種
操作

契約アサーション (C++26から)

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

契約アサーションは、プログラムの実行中の特定の時点で成立することが期待されるプログラムの状態に関するプロパティを、プログラマが指定できるようにするものです。

目次

[編集] 解説

契約アサーション (Contract assertions)は、関数契約指定子contract_assert文によって導入されます。各契約アサーションは、bool型の式である述語 (predicate) を持ちます。

[編集] 契約アサーションの評価

契約アサーションの評価は、以下の評価セマンティクスのいずれかを使用します。

評価セマンティクス チェックセマンティクスであるか 終了セマンティクスであるか
ignore
observe はい
enforce はい はい
quick-enforce はい はい

契約アサーションの特定の評価に対してどの評価セマンティクスが使用されるかは、処理系定義です。評価セマンティクスは、定数評価中を含め、同じ契約アサーションの異なる評価の間で異なる可能性があります。

"ignore"セマンティクスが使用された場合、契約アサーションの評価は何も効果を持ちません。

チェックセマンティクスが使用された場合、契約アサーションの評価Eは述語の値を決定します。述語が評価されるかどうかは未規定です。以下のいずれかの条件が満たされた場合、契約違反 (contract violation) が発生します。

  • 述語を評価した結果の値がfalseである。
  • 述語の評価が例外によって終了した。
  • 述語の評価が明示的な定数評価コンテキストで実行され、かつ述語がコア定数式ではない。

Aより前に発生する他のいかなる操作OPCPより前に発生するような、Eより前に発生する観測可能なチェックポイント (observable checkpoint) 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の生存期間は、契約違反ハンドラの呼び出しが終了するまで持続します。

[編集] 契約によって終了させられたプログラム

プログラムが契約によって終了させられる (contract-terminated) とき、以下のいずれが発生するかは処理系定義です(コンテキストに依存します)。

[編集] 契約違反ハンドラ

プログラムの契約違反ハンドラ (contract-violation handler) は、::handle_contract_violationという名前の関数です。

void handle_contract_violation( std::contracts::contract_violation );
(C++26以降)
(任意でnoexcept)

デフォルト契約違反ハンドラ (default contract-violation handler) と呼ばれる契約違反ハンドラの定義は、処理系によって提供されます(標準ライブラリのヘッダではなく)。

契約違反ハンドラが置換可能 (replaceable)かどうかは処理系定義です。契約違反ハンドラが置換可能でない場合、契約違反ハンドラの置換関数を宣言すると、プログラムは不適格となりますが、診断メッセージは要求されません。

契約違反ハンドラが正常にリターンした場合:

  • 評価セマンティクスが"observe"の場合、制御フローは契約アサーションの評価点の直後から正常に継続します。
  • 評価セマンティクスが"enforce"の場合、プログラムは契約によって終了させられます。

契約違反ハンドラが正常にリターンした後に発生する他のいかなる操作OPCPより後に発生するような、契約違反ハンドラが正常にリターンした後に発生する観測可能なチェックポイントCPが存在します。

[編集] アサーションからの例外の処理

述語の評価が例外によって終了したために契約違反が発生し、かつ評価セマンティクスが"observe"または"enforce"である場合、契約違反ハンドラはその例外に対するアクティブな暗黙のハンドラ内から呼び出されます。

契約違反ハンドラが正常にリターンした場合:

  • 評価セマンティクスが"observe"の場合、暗黙のハンドラはもはやアクティブであるとは見なされません。
  • 評価セマンティクスが"enforce"の場合、契約による終了が発生したときも暗黙のハンドラはアクティブなままです。

現在の例外は、契約違反ハンドラ内でstd::current_exception()を使用して調査したり、再送出したりすることができます。

[編集] 順次評価

契約アサーションのリストR順次評価 (evaluate in sequence) するには:

1) 以下のすべての条件を満たす契約アサーションのリストSを構築します。
  • Rのすべての要素がSに含まれる。
  • Rの各要素は、S内で処理系定義の回数だけ繰り返されることがある。
  • Rにおいて契約アサーションAが別の契約アサーションBより前にある場合、SにおいてもAの最初の出現はBの最初の出現より前にある。
2) Sの各要素を、Sにおいて契約アサーションAが契約アサーションBより前にある場合、Aの評価がBの評価より前に順序付けられる (sequenced before) ように評価します。
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)
}

[編集] 注釈

利用可能な評価セマンティクスの選択肢の範囲と柔軟性は処理系に依存し、4つすべての評価セマンティクスを可能性として許容する必要はありません。

契約アサーションが定数式によって生成される値を変更する副作用を持つ場合、異なる翻訳単位で同じ契約アサーションに対して異なる評価セマンティクスを選択すると、ODR違反 (one-definition rule) となる可能性があります。

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, pre, post

[編集] 関連項目

contract_assert (C++26) 実行中に内部条件を検証する[編集]
関数契約指定子 (C++26) 事前条件 (pre) と事後条件 (post) を指定する[編集]
English 日本語 中文(简体) 中文(繁體)