"std::bad_alloc": я использую слишком много памяти?
Сообщение:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Я посмотрел на обратную трассировку GDB, и это метод самого низкого уровня, который я реализовал сам:
/*
* 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;
}
Выражение cout, которое вы видите выше, указывает, что оно завершается после 7000+ итераций. Вышеуказанная функция вызывается только один раз в конце моего приложения. Я вызываю очень похожую функцию перед вызовом выше, это не вызывает проблем.
3 ответа
Моя проблема оказалась в том, что this->meshPoints.getNormalForVertex(i)
обращается к массиву (или к вектору, я не помню), длина которого меньше this->meshPoints.getNumFaces() * 3
, Так что доступ был за пределами.
(перемещение / расширение от комментариев)
Поскольку вы выделяете новый массив каждый раз, не освобождая его, у вас огромная утечка памяти, то есть вы продолжаете запрашивать память в системе, даже не возвращая ее. В конце концов пространство в куче заканчивается, и при следующем выделении все, что вы получите, это std::bad_alloc
исключение.
Решением "C-style" было бы помнить об освобождении такой памяти, когда она вам больше не нужна (с delete[]
), но это (1) подвержено ошибкам (например, если у вас есть несколько путей возврата внутри функции) и (2) потенциально небезопасно для исключения (каждая инструкция становится потенциальным путем возврата, если у вас есть исключения!). Таким образом, этого пути следует избегать.
Идиоматическое решение C++ состоит в том, чтобы использовать либо умные указатели - небольшие объекты, которые инкапсулируют указатель и освобождают ассоциированную память, когда они уничтожены, - либо стандартные контейнеры, которые делают более или менее то же самое, но с семантикой копирования и некоторыми другими наворотами (включая хранение размера массива внутри них).
Я получил эту ошибку при попытке выделить массив отрицательной длины:
double myArray = new double [-9000];
На всякий случай это кому-нибудь поможет.