Вот мой код:
void SurfaceManager::SurfaceManagerDelete()
{
for(map<string,SurfaceManager*>::iterator Iter = SurfaceList.begin(); Iter != SurfaceList.end(); ++Iter)
{
delete (*Iter).second;
(Iter) = SurfaceList.erase(Iter);
}
SurfaceList.clear();
}
Почему это вызывает несколько утечек памяти при сканировании с помощью VLD? Я знаю, что это как-то связано с тем, как я удаляю память из элемента именно этой строки «(Iter) = SurfaceList.erase (Iter);», однако я хотел бы знать, почему и как я должен правильно удалить элементы из списка.
Проблема в том, что ++ ++ Iter в цикле for. Это потому что
(Iter) = SurfaceList.erase(Iter);
уже обновляет Iter, чтобы указывать на элемент после стертого, как приращение.
Поэтому ++ Iter затем пропускает другой элемент, фактически вы удаляете все остальные элементы!
Вы должны позаботиться о том, чтобы работать с правильными итераторами. В вашем случае вы пропускаете один итератор из-за ++Iter
в for
цикл, и вы иногда будете в конечном итоге звонить ++
на конце итератор.
Обычно мутирующий ассоциативный контейнерный цикл выглядит так:
for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
if (delete_condition)
{
// other stuff, like "delete it->second;"m.erase(it++);
}
else
{
++it;
}
}
Кроме того, если вы утилизируете весь контейнер, не используйте erase
совсем:
for (auto & p : m) { delete p.second; }
// or alternatively
for (auto it = m.begin(); it != m.end(); ++it) { delete it->second; }
m.clear();
(Я хотел бы отметить, что я нашел только использование для clear()
на контейнере очень редко. Обычно в C ++ вы ограничиваете свои объекты так, чтобы они жили только в течение минимально необходимого времени, а когда вам нужна новая карта, вы просто создаете новую, а не очищаете и повторно используете тот, который живет слишком долго.)