The for loop deletes the elements in the map. The valgrind detection prompt is error: Invalid read of size 8, mapvalgrind.
1 #include <iostream> 2 #include <map> 3 4 using namespace std; 5 6 class A 7 { 8 public: 9 typedef std::map<int, string> myMap;10 11 void mapInsert(int i, string s)12 {13 map.insert(std::make_pair(i, s));14 }15 16 void deleteMap()17 {18 for (myMap::iterator it = map.begin(); it != map.end(); ++it)19 {20 map.erase(it->first);21 }22 }23 private:24 myMap map;25 };26 27 int main()28 {29 A a;30 a.mapInsert(1, "1");31 a.mapInsert(2, "2");32 a.mapInsert(3, "3");33 a.mapInsert(4, "4");34 a.mapInsert(5, "5");35 36 a.deleteMap();37 38 return 0;39 }
The above code compilation and running are all correct, but valgrind will prompt an error:
Valgrind -- tool = memcheck -- leak-check = full -- track-origins = yes./test #~ /Test ==723953 = Memcheck, a memory error detector = 723953 = Copyright (C) 2002-2012, and gnu gpl 'd, by Julian Seward et al. = 723953 = Using Valgrind-3.8.1 and LibVEX; rerun with-h for copyright info = 723953 = Command:./test = 723953 = = 723953 = Invalid read of size 8 = 723953 = at 0x3431C69E60: std: _ Rb_tree_increment (std: _ Rb_tree_node_base *) (tree. cc: 60) = 723953 = by 0x40131C: std: _ Rb_tree_iterator <std: pair <int const, std: string >:: operator ++ () (in/home/thm/test) = 723953 = by 0x40117C: A: deleteMap () (in/home/thm/test) = 723953 = by 0x400F4B: main (in/home/thm/test) ==723953 = Address 0x4c580b8 is 24 bytes inside a block of size 48 free 'd = 723953 = at 0x4A06016: operator delete (void *) (vg_replace_malloc.c: 480) = 723953 = by 0x401E23: _ gnu_cxx: new_allocator <std: _ Rb_tree_node <std: pair <int const, std: string >> :: deallocate (std: _ Rb_tree_node <std: pair <int const, std: string> *, unsigned long) (in/home/thm/test) = 723953 = by 0x401C99: std: _ Rb_tree <int, std: pair <int const, std: string>, std: _ Select1st <std :: pair <int const, std: string >>, std: less <int>, std: allocator <std: pair <int const, std :: string >>::_ M_put_node (std: _ Rb_tree_node <std: pair <int const, std: string >> *) (in/home/thm/test) = 723953 = by 0x401AA6: std: _ Rb_tree <int, std: pair <int const, std: string>, std: _ Select1st <std :: pair <int const, std: string >>, std: less <int>, std: allocator <std: pair <int const, std :: string >>>:: _ M_destroy_node (std: _ Rb_tree_node <std: pair <int const, std: string >> *) (in/home/thm/test) = 723953 = by 0x401729: std: _ Rb_tree <int, std: pair <int const, std: string>, std: _ Select1st <std:: pair <int const, std: string >>, std: less <int>, std: allocator <std: pair <int const, std :: string >>:: erase (std: _ Rb_tree_iterator <std: pair <int const, std: string>) (in/home/thm/test) = 723953 = by 0x40134C: std: map <int, std: string, std: less <int>, std: allocator <std :: pair <int const, std: string >>:: erase (std: _ Rb_tree_iterator <std: pair <int const, std: string>) (in/home/thm/test) = 723953 = by 0x401170: A: deleteMap () (in/home/thm/test) = 723953 = by 0x400F4B: main (in/home/thm/test) = 723953 = = 723953 = Invalid read of size 8 = 723953 = at 0x3431C69E80: std: _ Rb_tree_increment (std: _ Rb_tree_node_base *) (tree. cc: 68) = 723953 = by 0x40131C: std: _ Rb_tree_iterator <std: pair <int const, std: string >:: operator ++ () (in/home/thm/test) = 723953 = by 0x40117C: A: deleteMap () (in/home/thm/test) = 723953 = by 0x400F4B: main (in/home/thm/test) ==723953 = Address 0x4c580a8 is 8 bytes inside a block of size 48 free 'd = 723953 = at 0x4A06016: operator delete (void *) (vg_replace_malloc.c: 480) = 723953 = by 0x401E23: _ gnu_cxx: new_allocator <std: _ Rb_tree_node <std: pair <int const, std: string >> :: deallocate (std: _ Rb_tree_node <std: pair <int const, std: string> *, unsigned long) (in/home/thm/test) = 723953 = by 0x401C99: std: _ Rb_tree <int, std: pair <int const, std: string>, std: _ Select1st <std :: pair <int const, std: string >>, std: less <int>, std: allocator <std: pair <int const, std :: string >>::_ M_put_node (std: _ Rb_tree_node <std: pair <int const, std: string >> *) (in/home/thm/test) = 723953 = by 0x401AA6: std: _ Rb_tree <int, std: pair <int const, std: string>, std: _ Select1st <std :: pair <int const, std: string >>, std: less <int>, std: allocator <std: pair <int const, std :: string >>>:: _ M_destroy_node (std: _ Rb_tree_node <std: pair <int const, std: string >> *) (in/home/thm/test) = 723953 = by 0x401729: std: _ Rb_tree <int, std: pair <int const, std: string>, std: _ Select1st <std:: pair <int const, std: string >>, std: less <int>, std: allocator <std: pair <int const, std :: string >>:: erase (std: _ Rb_tree_iterator <std: pair <int const, std: string>) (in/home/thm/test) = 723953 = by 0x40134C: std: map <int, std: string, std: less <int>, std: allocator <std :: pair <int const, std: string >>:: erase (std: _ Rb_tree_iterator <std: pair <int const, std: string>) (in/home/thm/test) = 723953 = by 0x401170: A: deleteMap () (in/home/thm/test) = 723953 = by 0x400F4B: main (in/home/thm/test) = 723953 = = 723953 = ==723953 === heap summary: = 723953 = in use at exit: 0 bytes in 0 blocks = 723953 = total heap usage: 10 allocs, 10 frees, 370 bytes allocated = 723953 = = 723953 = All heap blocks were freed -- no leaks are possible = 723953 = = 723953 = For counts of detected and suppressed errors, rerun with:-v = 723953 = error summary: 8 errors from 2 contexts (suppressed: 6 from 6)
|
Why?
This code can implement functional requirements, but the robustness is not good. Assume that the current iterator of map is used again after map. erase, that is
void deleteMap() { for (myMap::iterator it = map.begin(); it != map.end(); ++it) { map.erase(it->first); std::cout << "map.first=" << it->first << " map.second=" << it->second << std::endl; } }
An error occurs when the code is running, because the object to which it currently points has been deleted.
To avoid such errors, we should ensure that iterator has moved forward one before the object pointed to by iterator is deleted.
The program can be changed to the following:
void deleteMap() { for (myMap::iterator it = map.begin(); it != map.end();) { map.erase(it++->first); } }
Or
void deleteMap() { for (myMap::iterator it = map.begin(); it != map.end();) { int i = it->first; ++it; map.erase(i); } }