メモリ確保に失敗したとき、戻り値だけでエラーを返すと、呼び出し元がチェックを忘れて後続処理でクラッシュすることがあります。MFCではAfxThrowMemoryException() を使うことで、CMemoryExceptionとして上位層へ伝え、メモリ不足の処理を1か所に集約できます。
この記事では、独自の確保処理やバッファ管理でメモリ不足を検出したときに、MFCの例外処理へ自然につなげるパターンを整理します。
まず確認すること
| 状況 | 使うもの | 理由 |
|---|---|---|
| MFCのnewが失敗した | CMemoryException* をcatch | MFCのメモリ例外として処理する |
| HeapAlloc / malloc / 独自プールが失敗した | AfxThrowMemoryException() | 戻り値エラーではなく、MFCの例外経路へ統一する |
| C++ catch (CMemoryException* e) で受けた | e->Delete() | C++ catchではMFC例外が自動削除されない |
| キャッシュや一時データを持っている | 解放してからユーザーへ通知 | 回復できる余地を先に作る |
CException::Delete() の所有権ルールは、【MFC】CException::Delete: なぜDelete() 呼び出しが必須かで詳しく整理しています。
MFCのメモリ例外
MFCのメモリ確保では、メモリ不足時にCMemoryExceptionが使われます。C++ 標準のstd::bad_allocとは別系統なので、MFC例外としてCMemoryException* を捕捉します。
try
{
CString* pText = new CString(_T("sample"));
delete pText;
}
catch (CMemoryException* e)
{
AfxMessageBox(_T("メモリが不足しています"));
// C++ catch では自動削除されないため必要
e->Delete();
}
自分でメモリ例外をスローする
独自のメモリ確保ロジックで失敗した場合にも、MFCの例外処理に合わせてCMemoryExceptionを投げられます。たとえばHeapAllocがNULLを返したときにAfxThrowMemoryException() を使います。
void* CMyPool::Allocate(size_t nSize)
{
void* p = ::HeapAlloc(::GetProcessHeap(), 0, nSize);
if (!p)
{
AfxThrowMemoryException();
}
return p;
}
AfxThrowMemoryException() は、メモリ不足という状況をMFCのCMemoryExceptionとして上位へ伝えるための関数です。呼び出し元は、MFCの他の例外と同じ形でcatch (CMemoryException* e) できます。
その他のAfxThrow関数
| 関数 | 例外クラス | 用途 |
|---|---|---|
| AfxThrowMemoryException | CMemoryException | メモリ不足 |
| AfxThrowFileException | CFileException | ファイル操作エラー |
| AfxThrowArchiveException | CArchiveException | シリアライズエラー |
| AfxThrowResourceException | CResourceException | リソース読み込みエラー |
| AfxThrowOleException | COleException | OLE / COMエラー |
メモリ不足時の対処パターン
メモリ不足を捕捉したら、可能であればキャッシュや一時データを解放してから、ユーザーに再試行や終了を促します。
BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
try
{
LoadLargeData(lpszPathName);
}
catch (CMemoryException* e)
{
e->Delete();
FreeCache();
m_data.clear();
AfxMessageBox(_T("メモリが不足しています。\n")
_T("他のアプリケーションを閉じてから再試行してください。"),
MB_ICONERROR);
return FALSE;
}
return TRUE;
}
ここで重要なのは、メモリ不足の発生元ではなく、処理を継続するかどうかを判断できる上位層でユーザーに通知することです。下位の層ではAfxThrowMemoryException() で通知し、上位層で画面表示や復旧処理を行います。
まとめ
- AfxThrowMemoryException() は、メモリ不足をCMemoryExceptionとして上位へ伝えるために使います
- 独自の確保処理で失敗したときも、MFCの例外経路に統一できます
- C++ catch (CMemoryException* e) で受けたら、処理後にe->Delete() を呼びます
- メモリ不足時は、可能な範囲でキャッシュや一時データを解放してからユーザーに通知します
