メモリ確保に失敗したとき、戻り値だけでエラーを返すと、呼び出し元がチェックを忘れて後続処理でクラッシュすることがあります。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()を呼びます - メモリ不足時は、可能な範囲でキャッシュや一時データを解放してからユーザーに通知します
