web-dev-qa-db-fra.com

comment intercepter une exception de mémoire en c ++?

quelqu'un peut-il me dire comment rattraper l'exception de mémoire?

par ex.

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

et aussi ça,

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

Capture std::bad_alloc .

Vous aurez également besoin d'une stratégie pour gérer les erreurs, car la plupart des choses que vous souhaitez faire nécessitent de la mémoire (même si c'est uniquement pour afficher une erreur à l'utilisateur avant de fermer). Une stratégie consiste à allouer un bloc de mémoire au démarrage, et delete dans le gestionnaire d'exceptions avant d'essayer d'utiliser plus de mémoire, donc qu'il existe certains disponibles à utiliser.

49
Mark Ransom

Comme d'autres l'ont noté, ce que vous voulez attraper, c'est std::bad_alloc. Vous pouvez également utiliser catch(...) ou catch(exception& ex) pour intercepter toute exception; ce dernier permet aux données d'exception d'être lues et utilisées dans le gestionnaire d'exceptions.

Mark Ransom avait déjà souligné que lorsque le programme ne peut plus allouer de mémoire, même l'impression d'un message d'erreur peut échouer. Considérez le programme suivant:

#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
}

(Je recommande fortement que le programme soit compilé en 32 bits pour éviter de manquer de mémoire sur une machine 64 bits. Les programmes 32 bits ne peuvent pas allouer plus de 4 Go de mémoire, ou 2 Go par défaut sous Windows.)

Lorsque le premier bad_alloc Est jeté dans la boucle infinie while, le contrôle est passé au bloc catch, mais le programme échoue toujours avec une exception non gérée. Pourquoi? Un autre bad_alloc Est jeté à l'intérieur du gestionnaire d'exceptions tout en essayant d'imprimer sur cerr. Vous pouvez le vérifier en utilisant un débogueur: définissez un point d'arrêt sur la ligne catch(bad_alloc& ex), exécutez le programme dans le débogueur, puis parcourez chaque instruction une fois que vous atteignez le point d'arrêt. Une exception bad_alloc Sera levée dans l'instruction cerr.

En tant que tel, pour gérer correctement un scénario de mémoire insuffisante, vous devez mettre de côté de la mémoire afin de pouvoir imprimer un message d'erreur avant de quitter. Sinon, le programme se bloquera simplement sur une exception non gérée lors de la tentative d'impression du message d'erreur. Pour ce faire, vous pouvez allouer un bloc de mémoire qui est désalloué dans le gestionnaire d'exceptions, comme l'a suggéré 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;
}

Vous devriez lire le commentaire de bdonlan. L'appel à cerr peut très bien échouer. La suggestion de Mark Ransom dans sa réponse est une bonne stratégie pour atténuer ce problème.

14
GWW

Vous devez catch un objet de type std::bad_alloc.

Alternativement, vous pouvez également utiliser une version nothrow de new comme:

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

Lorsque vous utilisez cela, aucune exception n'est levée si le new échoue. Au lieu de cela, il renvoie simplement NULL que vous vérifiez avant de poursuivre.

5
Nawaz