std :: map повторять и удалять ошибки valgrind

0

У меня есть простая программа, которая удаляет элементы на std :: map, итерации по карте. Если я не ошибаюсь, итераторы не аннулируются путем удаления на карте. Но valgrind вызывает недопустимые ошибки чтения. Может кто-нибудь объяснить, почему.

#include <map>
#include <iostream>

typedef std::map<std::string, int> SourceMap;
int main(int argc, char *argv[])
{
    SourceMap sourceMap;
    sourceMap["item1"] = 1;
    sourceMap["item2"] = 2;
    sourceMap["item3"] = 3;
    sourceMap["item4"] = 4;


    for(SourceMap::const_iterator it=sourceMap.begin(); it != sourceMap.end(); ++it)
    {
        sourceMap.erase(it->first);
    }
}

Ошибки Valgrind:

==31703== Invalid read of size 8
==31703==    at 0x3851069E60: std::_Rb_tree_increment(std::_Rb_tree_node_base*) (in /usr/lib64/libstdc++.so.6.0.13)
==31703==    by 0x4013D6: std::_Rb_tree_const_iterator<std::pair<std::string const, int> >::operator++() (stl_tree.h:259)
==31703==    by 0x40106B: main (map_iterator.cpp:14)
==31703==  Address 0x4c2c0b8 is 24 bytes inside a block of size 48 free'd
==31703==    at 0x4A0545F: operator delete(void*) (vg_replace_malloc.c:387)
==31703==    by 0x402821: __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::string const, int> > >::deallocate(std::_Rb_tree_node<std::pair<std::string const, int> >*, unsigned long) (new_allocator.h:95)
==31703==    by 0x402103: std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::_M_put_node(std::_Rb_tree_node<std::pair<std::string const, int> >*) (stl_tree.h:363)
==31703==    by 0x4017D0: std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::_M_destroy_node(std::_Rb_tree_node<std::pair<std::string const, int> >*) (stl_tree.h:384)
==31703==    by 0x4027AB: std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::erase(std::_Rb_tree_iterator<std::pair<std::string const, int> >) (stl_tree.h:1348)
==31703==    by 0x401FF2: std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::erase(std::_Rb_tree_iterator<std::pair<std::string const, int> >, std::_Rb_tree_iterator<std::pair<std::string const, int> >) (stl_tree.h:1388)
==31703==    by 0x4016A7: std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::erase(std::string const&) (stl_tree.h:1374)
==31703==    by 0x40141C: std::map<std::string, int, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::erase(std::string const&) (stl_map.h:582)
==31703==    by 0x40105C: main (map_iterator.cpp:16)
==31703==
==31703==
==31703== HEAP SUMMARY:
==31703==     in use at exit: 0 bytes in 0 blocks
==31703==   total heap usage: 8 allocs, 8 frees, 312 bytes allocated
==31703==
==31703== All heap blocks were freed -- no leaks are possible
  • 0
    If I am not wrong forward iterators are not invalidated by erase in a map . Вы не правы . Вы можете использовать возвращаемое значение erase для итератора для элемента после только что удаленного элемента. В этом конкретном случае вы можете просто использовать map::clear() .
Теги:
valgrind

2 ответа

7
Лучший ответ

Это обсуждалось до смерти. Вы не должны использовать недействительные итераторы. Напишите так:

for(SourceMap::const_iterator it = sourceMap.begin();
    it != sourceMap.end();  /* no hoist */
   /* no increment */ )
{
    sourceMap.erase(it++);
}

В качестве альтернативы:

// as before
{
    it = sourceMap.erase(it);
}

Или еще (пока у вас нет никаких условий для стирания):

sourceMap.clear();
0

Вы делаете что-то ужасно неправильно:

Итерируя по карте, вы удаляете ключ, на который указывает текущий итератор. При этом вы аннулируете этот итератор.

map :: erase (iterator-> first) имеет тот же эффект, что и map :: erase (iterator), но последний более уместен и эффективен.

Примечание. См. Также ответ Kerrek SB.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню