как отловить нехватку памяти в с ++? - PullRequest
37 голосов
/ 13 октября 2011

Может кто-нибудь сказать, пожалуйста, как отловить исключение из памяти?

для примера.

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
}

Ответы [ 4 ]

48 голосов
/ 13 октября 2011

Улов std::bad_alloc.

Вам также понадобится стратегия для обработки ошибок, так как для многих вещей, которые вы хотели бы сделать, потребуется память (даже если она выводит сообщение об ошибке пользователю перед выключением). Одна из стратегий состоит в том, чтобы выделить блок памяти при запуске и delete его в обработчике исключений перед тем, как попытается использовать больше памяти, чтобы было доступно некоторое количество для использования.

18 голосов
/ 11 ноября 2012

Как уже отмечали другие, вы хотите поймать 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
}

( Я настоятельно рекомендую скомпилировать программу как 32-разрядную, чтобы избежать нехватки памяти системы на 64-разрядной машине. 32-разрядные программы не могут выделять более 4 ГБ памяти или 2 ГБ по умолчанию в Windows. )

Когда первый bad_alloc создается в бесконечном цикле while, управление передается в блок catch, но программа по-прежнему завершается ошибкой с необработанным исключением. Зачем? Другой bad_alloc выбрасывается в обработчик исключений при попытке печати на cerr. Вы можете проверить это с помощью отладчика: установите точку останова в строке catch(bad_alloc& ex), запустите программу в отладчике, а затем выполните каждый оператор, как только вы достигнете точки останова. Исключение bad_alloc будет добавлено в оператор cerr.

Таким образом, чтобы правильно обрабатывать сценарий нехватки памяти, вам необходимо выделить немного памяти, чтобы вы могли напечатать сообщение об ошибке перед выходом. В противном случае программа просто потерпит неудачу при необработанном исключении при попытке напечатать сообщение об ошибке. Для этого вы можете выделить блок памяти, который освобождается в обработчике исключений, как предложил Марк Рэнсом:

// 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);
}
//...
14 голосов
/ 13 октября 2011
catch (std::bad_alloc& ba){
    cerr << "bad_alloc caught: " << ba.what() << endl;
}

В качестве заметки вы должны прочитать комментарий bdonlan. Звонок на cerr вполне может быть неудачным. Предложение Марка Рэнсома в его ответе является хорошей стратегией для смягчения этой проблемы.

5 голосов
/ 13 октября 2011

Вы должны catch объект типа std::bad_alloc.

В качестве альтернативы, вы также можете использовать nothrow версию new как:

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

Когда выиспользуйте это, никакое исключение не выдается, если new терпит неудачу.Вместо этого он просто возвращает NULL, который вы проверили, прежде чем продолжить.

...