はじめに
プログラミングでは、「この関数が呼ばれるとき、このポインタはNULL
であってはならない」「この変数の値は、必ず正の数のはずだ」といった、コードが正しく動作するための前提条件が存在します。
C言語由来の <cassert>
(C++では <cassert>
) ヘッダーで提供される assert()
マクロは、このような「本来ありえないはずの状況」を検出するためのツールです。assert
は、プログラムの開発中(デバッグビルド)にこれらの前提条件をチェックし、もし条件が破られていれば、問題の箇所を特定しやすい形でプログラムを即座に停止させます。
assert
を使ったサンプルコード
このコードは、ポインタが NULL
でないことを assert
を使って表明(チェック)する関数を定義します。
完成コード
#include <iostream>
#include <cassert> // assertマクロを使うために必要
#include <string>
using namespace std;
// 文字列へのポインタを受け取り、その長さを表示する関数
// この関数は、引数のポインタがNULLでないことを前提としている
void print_length(const char* p_str) {
// 1. アサーション: p_strはNULLポインタであってはならない
assert(p_str != nullptr);
// assertを通過すれば、p_strが有効なポインタであることが(ある程度)保証される
cout << "文字列「" << p_str << "」の長さは " << strlen(p_str) << " です。" << endl;
}
int main() {
// OK: 有効なポインタを渡す
print_length("Hello");
// NG: NULLポインタを渡す
// デバッグビルドで実行すると、この次の行でアサーションが失敗し、プログラムが停止する
print_length(nullptr);
return 0;
}
コードの解説
assert(p_str != nullptr);
これがアサーションの核心部分です。
assert(真であるべき条件式);
- 機能:
assert
のカッコの中に、true
であることを期待する条件式を記述します。 - 動作:
- 条件式が
true
の場合: 何もせず、プログラムの実行は次の行に進みます。 - 条件式が
false
の場合: 「アサーション失敗 (Assertion failed)」というメッセージ(ファイル名、行番号、条件式を含む)を標準エラー出力に表示し、プログラムを強制終了します。
- 条件式が
print_length(nullptr)
を呼び出すと、p_str != nullptr
が false
となるため、assert
は失敗し、プログラムは停止します。これにより、開発者は「print_length
関数が、想定外のNULL
ポインタで呼び出された」というバグを即座に認識できます。
デバッグビルドとリリースビルド
assert
の最も重要な特徴は、デバッグビルドでのみ有効になるという点です。
ソースコードをコンパイルする際に、NDEBUG
(No Debug) というマクロを定義すると(リリースビルドでは通常、自動で定義されます)、全ての assert()
はプリプロセッサによってコードから完全に取り除かれます。
これにより、
- 開発中(デバッグビルド): 徹底的に前提条件をチェックし、バグを早期に発見する。
- 製品版(リリースビルド): アサーションのチェックによるパフォーマンスへの影響をゼロにする。 という、合理的な使い分けが可能になります。
まとめ
今回は、C++の assert
マクロを使って、プログラムの実行時アサーションを行う方法を解説しました。
assert(常に真であるべき条件)
という構文で記述する。- 条件が
false
になった瞬間に、プログラムを意図的に停止させ、バグの存在を知らせる。 - デバッグ時にのみ有効で、リリース版のパフォーマンスには影響しない。
assert
は、エラーハンドリング(予期されるエラーへの対処)とは異なり、あくまで「ありえないはずのバグ」を検出するための開発者向けのツールです。適切に使うことで、プログラムの堅牢性を大きく向上させることができます。