【MFC】AfxThrowMemoryException: メモリ確保失敗をMFC例外に統一する

【MFC】AfxThrowMemoryException: メモリ確保失敗を MFC 例外に統一する

メモリ確保に失敗したとき、戻り値だけでエラーを返すと、呼び出し元がチェックを忘れて後続処理でクラッシュすることがあります。MFCではAfxThrowMemoryException() を使うことで、CMemoryExceptionとして上位層へ伝え、メモリ不足の処理を1か所に集約できます。

この記事では、独自の確保処理やバッファ管理でメモリ不足を検出したときに、MFCの例外処理へ自然につなげるパターンを整理します。


目次

まず確認すること

状況使うもの理由
MFCのnewが失敗したCMemoryException* をcatchMFCのメモリ例外として処理する
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関数

関数例外クラス用途
AfxThrowMemoryExceptionCMemoryExceptionメモリ不足
AfxThrowFileExceptionCFileExceptionファイル操作エラー
AfxThrowArchiveExceptionCArchiveExceptionシリアライズエラー
AfxThrowResourceExceptionCResourceExceptionリソース読み込みエラー
AfxThrowOleExceptionCOleExceptionOLE / 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() を呼びます
  • メモリ不足時は、可能な範囲でキャッシュや一時データを解放してからユーザーに通知します
目次