Распределение памяти / повреждение кучи в конструкторе std :: string - PullRequest
1 голос
/ 02 июля 2011

У меня снова возникли проблемы с выделением памяти, и я не могу понять, почему.

Когда я запускаю программу в режиме отладки, я получаю следующее сообщение об ошибке (я пытался перевести его максимально точно):

Windows запустила точку останова в LogoColorDetector.exe. Это может быть вызвано повреждением кучи, которое указывает на проблему в LogoColorDetector.exe или в одной из загруженных библиотек DLL [...]

Когда я отлаживал программу, обнаружил, что проблема возникает в следующей строке:

std::string tmp = imgTrain2[j]->getFilepath();

Функция getFilepath () - реализована следующим образом:

const std::string& support::Image::getFilepath() const
{
    return this->_filePath;
}

Я уже проверил, имеет ли объект Image в imgTrain [j] правильную строку _filePath. Поэтому я предполагаю, что проблема в другом. Самое смешное, что функция, которая содержит проблемную строку, кажется, работает. Это только второй раз, когда я вызываю функцию, когда она выходит из строя, что указывает на то, что проблема не в самой функции. Я не выделяю память и не удаляю ничего в функции, кроме того, что может быть сделано косвенно через std :: string

В случае, если это поможет кому-то, вот трассировка стека:

msvcr100d.dll!_heap_alloc_base(unsigned int size)  Zeile 55 C
msvcr100d.dll!_heap_alloc_dbg_impl(unsigned int nSize, int nBlockUse, const char * szFileName, int nLine, int * errno_tmp)  Zeile 431 + 0x9 Bytes   C++
msvcr100d.dll!_nh_malloc_dbg_impl(unsigned int nSize, int nhFlag, int nBlockUse, const char * szFileName, int nLine, int * errno_tmp)  Zeile 239 + 0x19 Bytes   C++
msvcr100d.dll!_nh_malloc_dbg(unsigned int nSize, int nhFlag, int nBlockUse, const char * szFileName, int nLine)  Zeile 302 + 0x1d Bytes C++
msvcr100d.dll!malloc(unsigned int nSize)  Zeile 56 + 0x15 Bytes C++
msvcr100d.dll!operator new(unsigned int size)  Zeile 59 + 0x9 Bytes C++
LogoColorDetector.exe!std::_Allocate<char>(unsigned int _Count, char * __formal)  Zeile 36 + 0xf Bytes  C++
LogoColorDetector.exe!std::allocator<char>::allocate(unsigned int _Count)  Zeile 187 + 0xb Bytes    C++
LogoColorDetector.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Copy(unsigned int _Newsize, unsigned int _Oldlen)  Zeile 1933 + 0x12 Bytes C++
LogoColorDetector.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Grow(unsigned int _Newsize, bool _Trim)  Zeile 1963 + 0x13 Bytes   C++
LogoColorDetector.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & _Right, unsigned int _Roff, unsigned int _Count)  Zeile 902 + 0xe Bytes C++
LogoColorDetector.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & _Right)  Zeile 546 C++
LogoColorDetector.exe!compareClasses(support::ImageCollection * coll, support::ImageClass * cl1, support::ImageClass * cl2, float * mean, float * var)  Zeile 111 + 0x22 Bytes  C++

Кто-нибудь имеет представление о том, что может вызвать это?

Спасибо за вашу помощь.

- редактировать -

Попробовал предложение с помощью Visual Leak Detector. Он ничего не показывает, пока не появится вышеупомянутое сообщение об ошибке, в котором говорится, что память была изменена после освобождения. Есть ли способ узнать, какой объект был связан с адресом памяти - дамп памяти кажется не очень полезным.

Чтобы сделать вещи более загадочными, я попытался добавить следующую строку:

std::string tmp = imgTrain2[j]->getFilepath();
std::string t2Path = imgTrain2[j]->getFilepath();

Теперь первая строка выполнена правильно, а вторая строка не выполнена.

Ответы [ 2 ]

9 голосов
/ 02 июля 2011

Когда среда выполнения обнаруживает повреждение кучи, куча уже повреждена. Это означает, что предыдущая операция испортила ее (например, вы написали что-то за пределами массива, у вас есть поврежденные указатели и т. Д.).

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

Обновление : некоторые дополнения к ответу Дэвида (извините, ТАК не допускает длинных комментариев)

Для завершения аналогии: в вашей программе есть ошибка. Когда строка, содержащая ошибку, выполняется, это может привести к ошибке. Он перезаписывает часть кучи, в которой хранится информация о выделенных фрагментах памяти. Среда выполнения этого не распознает, этот сегмент памяти принадлежит вашему процессу, поэтому вы должны иметь возможность писать в него. Нет провала. Теперь позже (возможно, в совершенно другой части вашего приложения) вы пытаетесь выделить новую память, новый оператор вызывает heap_alloc_, чтобы получить новый фрагмент памяти. Код для alloc проходит через цепочку выделенных блоков памяти и находит там мусор. Это вызывает неспособность сообщить вам, что происходит что-то действительно плохое. Теперь вы должны найти ошибку в вашем коде, которая вызвала ошибку. Без какого-либо инструмента вы должны проверить весь код поиска ошибок.

3 голосов
/ 02 июля 2011

Когда вы удаляете кучу, то источник и обнаружение ошибки часто разделяются по местоположению и по времени.Между сбоями, ошибками и сбоями существует большая разница.

В качестве аналогии представьте, что в памяти немного битов, но по какой-то причине он переключается на постоянное зависание в одном состоянии.Это ошибка.Никаких последствий пока.Предположим, что следующая операция над битом - это команда.Команда скрыла свою вину;в некотором смысле проблема не существует.Читатели получат одно значение, правильное значение.Подайте команду на ноль, и ошибка снова станет реальной, но это не проблема.Проблема не проявляется, пока читатель не прочитает единицу, когда бит должен был быть нулевым.В этот момент ошибка вызвала ошибку.Это все еще не может быть проблемой;ошибка может не повлиять на то, что ошибочный бит оказался наименее значимым битом мантиссы из сохраненного значения числа пи.Некоторые битовые сбои вызывают проблемы.Например, ошибочный бит может привести к тому, что космический корабль оглохнет.Ошибка вызывает сбой, когда из-за ошибки система каким-то образом ведет себя плохо.

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

Я подозреваю, что где-то вдоль строки, которую вы написали в imgTrain2[j].Теперь у вас плохой указатель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...