45 votes

comment attraper une exception hors mémoire en c++ ?

Quelqu'un peut-il me dire comment attraper une exception de mémoire insuffisante ?

par exemple.

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

et aussi ceci,

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

59voto

Mark Ransom Points 132545

Attrapez std::bad_alloc .

Vous aurez également besoin d'une stratégie pour gérer les erreurs, car la plupart des choses que vous voudrez faire nécessiteront de la mémoire (même si ce n'est que pour afficher une erreur à l'utilisateur avant de s'arrêter). L'une des stratégies consiste à allouer un bloc de mémoire au démarrage, et à delete dans le gestionnaire d'exception avant en essayant d'utiliser plus de mémoire, afin qu'il y en ait de disponible à utiliser.

26voto

DragonLord Points 625

Comme d'autres l'ont noté, ce que vous voulez attraper est std::bad_alloc . Vous pouvez également utiliser catch(...) o catch(exception& ex) pour attraper n'importe quelle exception ; ce dernier permet de lire les données de l'exception et de les utiliser dans le gestionnaire d'exception.

Mark Ransom avait déjà fait remarquer que lorsque le programme ne peut plus allouer de mémoire, même l'impression d'un message d'erreur peut échouer. Considérons 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 vivement que le programme soit compilé en 32 bits pour éviter que le système ne manque 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 l'infini while le contrôle est transmis à la boucle catch mais le programme échoue toujours avec une exception non gérée. Pourquoi ? Un autre site bad_alloc est jeté dans le gestionnaire d'exception en essayant d'imprimer sur cerr . Vous pouvez le vérifier en utilisant un débogueur : Définissez un point d'arrêt à l'emplacement catch(bad_alloc& ex) exécutez le programme dans le débogueur, puis parcourez chaque instruction une fois que vous avez atteint le point d'arrêt. A bad_alloc L'exception sera déclenchée dans le cerr déclaration.

Ainsi, pour gérer correctement un scénario de dépassement de mémoire, vous devez réserver un peu de mémoire afin de pouvoir imprimer un message d'erreur avant de quitter. Sinon, le programme se bloquera sur une exception non gérée alors qu'il tente d'imprimer le message d'erreur. Pour ce faire, vous pouvez allouer un bloc de mémoire qui sera désalloué dans le gestionnaire d'exception, comme le suggère 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);
}
//...

14voto

GWW Points 20316
catch (std::bad_alloc& ba){
    cerr << "bad_alloc caught: " << ba.what() << endl;
}

À titre d'information, 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.

5voto

Nawaz Points 148870

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

Vous pouvez également utiliser un nothrow verison de new comme :

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X