std :: list удалить вызов удалить по указателю? - PullRequest
3 голосов
/ 30 июля 2010

Я запустил valgrind в моей программе из-за ошибки, которую я не могу понять.Здесь обнаружена проблема ...

Address 0x75c7670 is 0 bytes inside a block of size 12 free'd
  at 0x4024851: operator delete(void*) (vg_replace_malloc.c:387)
  by 0x805F6D8: std::list<Object*, std::allocator<Object*>::remove(O
  bject* const&) (new_allocator.h:95)

Удаление выполняется в этом методе ...

void ObjectManager::AdjustGridCoord( int x, int y, Object* const obj ) {
  // GetTileX and GetTileY guaranteed to be valid indices
  int newX = ObjectAttorney::GetTileX( obj );
  int newY = ObjectAttorney::GetTileY( obj );
  if ( x != newX || y != newY  ) {
    m_objGrid[x][y].remove( obj );
    m_objGrid[newX][newY].push_back( obj );
  }
} 

Я не думал, что удаление указателя из списка вызовет delete в теме.Что здесь выглядит подозрительно?Если вам нужна дополнительная информация, дайте мне знать.

PS Ранее при отладке я заметил, что проблема возникла из-за того, что GetTileX и GetTileY не были действительными индексами и возвращали смешные числа, например 13775864.Я думаю, что это связано с проблемой delete, и удаление или push_back вызывает проблему.

Редактировать: Вот еще один фрагмент кода

for ( unsigned int x = 0; x < m_objGrid.size(); ++x ) {
  for ( unsigned int y = 0; y < m_objGrid[x].size(); ++y ) {
    for ( ListItr obj = m_objGrid[x][y].begin(); obj != m_objGrid[x][y].end(); ++obj ) {
      ObjectAttorney::UpdateAI( *obj );
      AdjustGridCoord( x, y, *obj );
    }
  }
}

Может ли AdjustGridCoord сделать недействительнымитератор?

Ответы [ 2 ]

2 голосов
/ 30 июля 2010

В ответ на ваши изменения, да, я думаю, вы правильно его диагностировали.

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

m_objGrid[x][y].remove( obj );

, где вы удаляете объект obj, сделает недействительным итератор obj в вызывающей функции.Как видно из вывода valgrind, удаление объекта приводит к тому, что список удаляет ячейку, содержащую указатель объекта, на что ссылается итератор obj.Таким образом, итератор obj становится недействительным.Затем, когда вызов возвращается, самое следующее, что происходит, - это приращение цикла:

++obj

Здесь obj - это итератор, который был просто недействителен, и его ссылочная ячейка была удалена в вызове к AdjustGridCoord.Это вызывает доступ к памяти, которая была освобождена, на что жалуется valgrind.

У вас есть два варианта:

  1. Перестройте ваш цикл, чтобы получить последующийитератор до вы вызываете AdjustGridCoord
  2. Выполните итерацию по списку один раз и запишите, какие изменения необходимо внести в какую-то другую структуру данных, а затем выполните второй цикл над этим вторичным "списком изменений"", и внутри этого цикла на самом деле вносить эти изменения в исходный список.

Примером 2 может быть создание std::vector<std::pair<unsigned int, unsigned int> >, содержащего координаты, которые вам нужно вызвать AdjustGridCoord наи затем выполните итерацию, чтобы сделать вызовы.

1 голос
/ 30 июля 2010

Блок размером 12 free'd на самом деле является узлом списка, а не вашим объектом.Таким образом, std::list::remove() не вызвал delete для вашего указателя, он просто delete d для узла списка, содержащего его.

Я не могу сказать из ваших фрагментов кода, где вы на самом деле (неправильно) используетеэта память.

...