web-dev-qa-db-fra.com

"std :: bad_alloc": j'utilise trop de mémoire?

Le message: 

terminate called after throwing an instance of 'std::bad_alloc'
what():  std::bad_alloc

J'ai regardé la trace gdb et c'est la méthode de plus bas niveau que j'ai implémentée moi-même:

/*
 * get an array of vec3s, which will be used for rendering the image
 */
vec3 *MarchingCubes::getVertexNormalArray(){
    // Used the same array size technique as getVertexArray: we want indices to match     up
    vec3 *array = new vec3[this->meshPoints.getNumFaces() * 3]; //3 vertices per face

    int j=0;
    for (unsigned int i=0; i < (this->meshPoints.getNumFaces() * 3); i++) {
        realVec normal = this->meshPoints.getNormalForVertex(i);
 //     PCReal* iter = normal.begin();

        if (normal.size() >= 3) {
            array[j++] = vec3(normal[0], normal[1], normal[2]);
        }
        cout << i << " ";
    }

    return array;
}

L'instruction cout que vous voyez ci-dessus indique qu'elle se termine après plus de 7000 itérations ..__ La fonction ci-dessus n'est appelée qu'une fois vers la fin de mon application. J'appelle une fonction très similaire avant d'appeler ce qui précède, cela ne pose pas de problèmes.

10
Rooster

Mon problème s'est avéré que this->meshPoints.getNormalForVertex(i) accède à un tableau (ou un vecteur, je ne me souviens plus) dont la longueur est inférieure à this->meshPoints.getNumFaces() * 3. Donc, il y avait accès en dehors des limites.

3
Rooster

(se déplaçant/élargissant à partir des commentaires)

Comme vous allouez un nouveau tableau à chaque fois sans le désallouer, vous avez une fuite de mémoire massive, c’est-à-dire que vous continuez à demander de la mémoire au système sans jamais la restituer. Finalement, l'espace sur le tas se termine et lors de l'allocation suivante, vous obtenez une exception std::bad_alloc.

La solution de "style C" serait de ne pas oublier de désallouer une telle mémoire lorsque vous n'en avez plus besoin (avec delete[]), mais c'est (1) une source d'erreurs (pensez par exemple si vous avez plusieurs chemins de retour dans une fonction ) et (2) potentiellement exception-non sûre (chaque instruction devient un chemin de retour potentiel si vous avez des exceptions!). Ainsi, cette façon devrait être évitée.

La solution idiomatique C++ consiste à utiliser soit les pointeurs intelligents - les petits objets qui encapsulent le pointeur et libèrent la mémoire associée lorsqu'ils sont détruits - ou des conteneurs standard, qui font plus ou moins la même chose mais avec une sémantique de copie et quelques autres cloches et sifflets (y compris stocker la taille du tableau à l'intérieur).

21
Matteo Italia

J'ai eu cette erreur en essayant d'allouer un tableau de longueur négative:

double myArray = new double [-9000];

Juste au cas où cela aiderait quelqu'un. 

2
Tim Mottram