【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 を投げられます。たとえば HeapAllocNULL を返したときに 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() を呼びます
  • メモリ不足時は、可能な範囲でキャッシュや一時データを解放してからユーザーに通知します
目次