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 やローカル変数を見れば、どの前提が崩れたかをその場で確認できます。
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では消える
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では消えるため、副作用のある処理は中に書かないでください。
