web-dev-qa-db-ja.com

C ++でメモリ不足の例外をキャッチする方法は?

誰かがメモリ不足の例外をキャッチする方法を教えてもらえますか?

例えば.

try
{
    while(true)
    {
        int i = new int;
    }
}
catch( ? <--- what should be put here?)
{
    //exception handling
}

そしてこれも

queue<int> q;
try
{
     while(true)
     {
          q.Push(10);
     }
}
catch( ? <---- what should be put here?)
{
     //error handling
}
37
in His Steps

キャッチ std::bad_alloc

エラーを処理するための戦略も必要になります。実行したいことの多くはメモリを必要とするためです(シャットダウンする前にユーザーにエラーを表示するだけの場合でも)。 1つの戦略は、起動時にメモリブロックを割り当て、それを例外ハンドラbeforedelete割り当てて、より多くのメモリを使用しようとするため、使用可能なものがあること。

49
Mark Ransom

他の人が指摘したように、キャッチしたいのは_std::bad_alloc_です。 catch(...)またはcatch(exception& ex)を使用して、例外をキャッチすることもできます。後者の場合、例外データを読み取り、例外ハンドラーで使用できます。

マークランサムは、プログラムがこれ以上メモリを割り当てることができない場合、エラーメッセージの印刷でさえ失敗する可能性があることをすでに指摘していました。次のプログラムを検討してください。

_#include <iostream>

using namespace std;

int main() {
    unsigned long long i = 0;
    try {
        while(true) {
            // Leaks memory on each iteration as there is no matching delete
            int* a = new int;
            i++;
        }
    } catch(bad_alloc& ex) {
        cerr << sizeof(int) * i << " bytes: Out of memory!";
        cin.get();
        exit(1);
    }

    return 0; // Unreachable
}
_

64ビットマシンでシステムがメモリ不足になるのを防ぐため、プログラムを32ビットとしてコンパイルすることを強くお勧めします。32ビットプログラムは4 GB以上、またはデフォルトで2 GB以上のメモリを割り当てることはできませんWindowsの場合

最初の_bad_alloc_が無限のwhileループでスローされると、制御はcatchブロックに渡されますが、プログラムは未処理の例外で失敗します。どうして?別の_bad_alloc_がスローされます例外ハンドラー内cerrに出力しようとしています。これは、デバッガーを使用して確認できます。catch(bad_alloc& ex)行にブレークポイントを設定し、デバッガーでプログラムを実行し、ブレークポイントに到達したら各ステートメントをステップ実行します。 cerrステートメントで_bad_alloc_例外がスローされます。

そのため、メモリ不足のシナリオを適切に処理するには、終了する前にエラーメッセージを出力できるようにメモリを確保する必要があります。それ以外の場合、プログラムは、エラーメッセージを出力しようとしているときに、未処理の例外でクラッシュするだけです。そのためには、Mark Ransomが提案したように、例外ハンドラーで割り当て解除されたメモリブロックを割り当てることができます。

_// Reserve 16K of memory that can be deleted just in case we run out of memory
char* _emergencyMemory = new char[16384];
// ...
try {
// ...
} catch(bad_alloc& ex) {
    // Delete the reserved memory so we can print an error message before exiting
    delete[] _emergencyMemory;

    cerr << sizeof(int) * i << " bytes: Out of memory!";
    cin.get();
    exit(1);
}
//...
_
18
bwDraco
catch (std::bad_alloc& ba){
    cerr << "bad_alloc caught: " << ba.what() << endl;
}

メモとして、bdonlanのコメントを読んでください。 cerrの呼び出しは非常に失敗する可能性があります。 Mark Ransomの答えでの提案は、この問題を緩和するための優れた戦略です。

14
GWW

catch型のオブジェクトstd::bad_alloc

または、nothrownewバージョンを次のように使用することもできます。

int *pi = new (nothrow) int[N]; 
if(pi == NULL) 
{
   std::cout << "Could not allocate memory" << std::endl;
}

これを使用すると、newが失敗しても例外はスローされません。代わりに、単に先に進む前に確認するNULLを返すだけです。

5
Nawaz