最終更新日時(UTC):
が更新

履歴 編集

macro
<cassert>

assert

# if !defined(NDEBUG)
  #define assert(expr) implementation-defined // (1) C++03
  #define assert(...) implementation-defined  // (1) C++26
# else
  #define assert(ignore) ((void)0)            // (2) C++03
  #define assert(...) ((void)0)               // (2) C++26
# endif

概要

式が真であることを表明する。

このマクロは、開発時に除去できるバグを見つけるために使用できる。「関数の引数がある範囲内の値でなければならない」「ある状態でこの関数を呼び出してはならない」といったことを表明することで、その関数を呼び出すユーザーに対する要件として設定できる。

このマクロは、直前の<cassert>(または<assert.h>)のインクルード時点でマクロNDEBUGが定義されていなかった場合に有効となり、NDEBUGが定義されていた場合は無効となる。

要件

  • C++14まで : パラメータの式の型はスカラ型でなければならない
    • C言語への参照として定義されていた仕様では、assertvoid assert(scalar expression);のような関数として定義されていた

効果

  • 有効な場合:
    • C++03 : パラメータの式を評価し、
    • C++26 : 可変引数パラメータ__VA_ARGS__boolに変換し、
    • 真に評価された場合は、なにもしない
    • そうでない場合(0と等しい場合)、式をテキスト化したもの、(std::source_location::current()で取得できるような) ソースファイル名、行番号、関数名を標準エラー出力に処理系定義の書式で書き込み、abort()関数を呼び出してプログラムを異常終了させる
  • 無効な場合:
    • パラメータの式は評価はされず、なにもしない

このマクロは、定数式内で使用できる。(C++17)

備考

有効・無効に関わらずvoid型の式となる(文などにはならない)ので、カンマ演算子と組み合わせるなどして、式が書けるところならどこにでも記述することができる。

マクロNDEBUGは、標準C++の言語およびライブラリでは定義しない。開発環境やユーザーが定義することとなる。NDEBUGを定義せずassertを有効にした設定を「デバッグビルド」、NDEBUGを定義してassertを無効にした設定を「リリースビルド」などととして複数のビルド設定を持つ開発環境がある。

マクロNDEBUGの定義の状態を変えて<cassert>をインクルードしなおすことで翻訳単位中で有効・無効を切り替えることも可能である。

実行環境や入力によって起こりえるエラーに対するエラー処理としてこのマクロを使用すると無効化された場合に意図しない動作となることがあるので、別な手段として、例外、bool型の返却値などを検討すること。

assertマクロの基本的な使い方

#include <cassert>

void f(int x)
{
  // パラメータxは、正数でなければならない
  assert(x >= 0);

  // …xを使った処理…
}

int main()
{
  f(3);  // OK
  f(-1); // プログラムが異常終了する
}

出力例

prog.exe: prog.cc:6: void f(int): Assertion `x >= 0' failed.

定数式としてassertマクロを使用する (C++17)

#include <cassert>

constexpr int f(int x)
{
  assert(x >= 0); // constexpr関数内に式としてassertマクロを使用する
  return x + 1;
}

int main()
{
  constexpr int a = f(1);
//constexpr int b = f(-1); // コンパイルエラー!
}

出力

カンマを含む条件式をassertマクロで使用する (C++26)

#include <cassert>
#include <type_traits>

template <class T>
void f()
{
  assert(std::is_same_v<int, T>);   // C++26 : OK
  assert((std::is_same_v<int, T>)); // C++23までは、カンマを含む式は全体を丸カッコで囲む必要がある
}

int main()
{
  f<int>();
  f<double>();
}

出力

参照