• for循环中删除map中的元素,valgrind检测提示error:Invalid read of size 8


     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 }

    上述代码编译运行皆没有问题,但是用valgrind检测会提示错误:

    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/test)
    ==723953==    by 0x40117C: A::deleteMap() (in /home/thm/test/test)
    ==723953==    by 0x400F4B: main (in /home/thm/test/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/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/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/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/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/test)
    ==723953==    by 0x401170: A::deleteMap() (in /home/thm/test/test)
    ==723953==    by 0x400F4B: main (in /home/thm/test/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/test)
    ==723953==    by 0x40117C: A::deleteMap() (in /home/thm/test/test)
    ==723953==    by 0x400F4B: main (in /home/thm/test/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/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/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/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/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/test)
    ==723953==    by 0x401170: A::deleteMap() (in /home/thm/test/test)
    ==723953==    by 0x400F4B: main (in /home/thm/test/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?

    此代码可以实现功能要求,但是健壮性并不好,假设在map.erase之后再次使用map当前的iterator,即

        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;
            }
        }

    代码运行就会出现错误,因为it目前指向的对象已经被删掉了。

    为了避免程序出现这样的错误,我们应该保证在iterator指向的对象被删掉之前,iterator已经向前移位一

    程序改成如下即可:

        void deleteMap()
        {
            for (myMap::iterator it = map.begin(); it != map.end();)
            {
                map.erase(it++->first);
            }
        }

        void deleteMap()
        {
            for (myMap::iterator it = map.begin(); it != map.end();)
            {
                int i = it->first;
                ++it;
                map.erase(i);
            }
        }
  • 相关阅读:
    从C#到TypeScript
    从C#到TypeScript
    从C#到TypeScript
    从C#到TypeScript
    UWP开源项目 LLQNotifier 页面间通信利器(移植EventBus)
    .net源码分析
    读读日报小布版 计划与反馈
    Pyinstaller使用
    Pyspider安装使用
    元器件资料查看网站
  • 原文地址:https://www.cnblogs.com/tanghuimin0713/p/5651639.html
Copyright © 2020-2023  润新知