ASSERTで止まった場所は、前提が崩れた場所です。ここで止まるなら、その少し前から値か状態がおかしくなっています。
この記事では、Debug Assertion Failed! ダイアログの見方と、Releaseで消える性質を前提にASSERTをどう置くかを整理します。
最初に見るポイント
- ASSERTはDebugビルドでだけ有効です。Releaseでは消えます。
- ダイアログが出たら、「再試行 (Retry)」 で止めると、その行から原因を追えます。
- ASSERTの中に、副作用のある処理を書いてはいけません。
ASSERTが失敗するとどうなるか
たとえば、次のようなコードがあるとします。
void CMFCDebugSandboxDlg::OnBnClickedBtnAssert()
{
int* pNullPointer = NULL;
ASSERT(pNullPointer != NULL);
*pNullPointer = 100;
}
pNullPointerは明らかにNULLです。ここでASSERTが失敗し、Debug Assertion Failed! ダイアログが出ます。

このダイアログで 「再試行 (Retry)」 を押すと、Visual StudioがASSERTの行で停止します。ここからCall Stackやローカル変数を見れば、どの前提が崩れたかをその場で確認できます。
ダイアログに表示されるFile / Line / Expressionの読み方は、【MFC】Debug Assertion Failed! の正しい読み方で詳しく整理しています。
ダイアログが出ると、自分で置いたASSERTが止めたのだと思いがちですが、1行目が「Debug」の付かない「Assertion failed!」なら、C/C++標準のassert()が止めています。「Debug Assertion Failed!」でもExpressionの行に式が出ていれば、_ASSERTEのようなCランタイムのデバッグ用マクロが止めています(MFCのASSERTのダイアログにはExpressionの行がありません)。assert()はNDEBUGが定義されていなければReleaseでも動くので、次の「Releaseでは消える」は当てはまりません。見分け方はAssertion failed!の読み方:assert()とDebug Assertion Failed!の見分け方に書いています。
ASSERTに書く式
関数に入ったときや値を書き換えた後に必ず成り立つ、という条件をASSERTに書きます。処理そのものではなく、処理の前後で値がおかしくなっていないかを確かめる式です。
void CMyView::OnDraw(CDC* pDC)
{
ASSERT(pDC != NULL);
// 描画処理
}
void CPlayer::TakeDamage(int nDamage)
{
ASSERT(nDamage >= 0);
m_nHP -= nDamage;
ASSERT(m_nHP >= 0);
}
このように、NULLでないこと、負の値が入らないこと、添字が範囲内であることなど、前提条件の確認に使います。
Releaseでは消える
開発中だけ走らせたい重い整合チェックや、全オブジェクトの状態を1つずつ調べる確認は、ASSERTの中に書いておけます。ASSERTはReleaseビルドでは評価されません。
void CGameManager::Update()
{
ASSERT(VerifyAllObjectsStateAreValid());
// 通常の更新処理
}
この書き方なら、Debugでは整合を強く確認し、Releaseでは動作を変えずに本処理だけを走らせられます。
副作用を入れない
Releaseで消える以上、ASSERTの中に処理本体を書いてはいけません。ここを混ぜると、Debugでだけ動いてReleaseで壊れます。
// NG
ASSERT(m_file.Open(_T("data.txt"), CFile::modeRead) != FALSE);
この書き方だと、ReleaseではOpen自体が実行されません。結果として、Releaseでだけファイルを開かない不具合になります。
処理と確認は分けてください。
BOOL bOpened = m_file.Open(_T("data.txt"), CFile::modeRead);
ASSERT(bOpened != FALSE);
※ VERIFYを使う方法もありますが、まずは「処理は外、確認だけASSERT」に揃える方が混乱しません。
まとめ
- ASSERTは、前提が崩れた場所で止めるための確認です。
- Debugでダイアログが出たら、「再試行 (Retry)」 で止めて、その場から追ってください。
- Releaseでは消えるため、副作用のある処理は中に書かないでください。
