代码之家  ›  专栏  ›  技术社区  ›  Satbir

迭代器有效性,在std::set中的erase()调用之后

  •  10
  • Satbir  · 技术社区  · 15 年前

    在std::set invalidate迭代器中是否清除调用?就像我在最后一行的第五行所做的那样…… 如果是,清除集合中所有元素的更好方法是什么?

    class classA
    {
    public:
        classA(){};
        ~classA(){};
    };
    struct structB
    {
    };
    
    typedef std::set <classA*, structB> SETTYPE;        
    typedef std::map <int, SETTYPE>MAPTYPE;
    
    int __cdecl wmain (int argc, wchar_t* pArgs[])
    {
        MAPTYPE mapObj; 
        /*
          ...
          ..   Some Operation Here
          ...
          */
        for (MAPTYPE::iterator itr1=mapObj.begin(); itr1!=mapObj.end(); itr1++) 
        {       
            SETTYPE li=(*itr1).second;
            for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++) 
            {
                classA *lt=(classA*)(*itr2);
                li.erase(itr2); 
                delete lt; // Does it invalidate Iterator ?
            }
        }
    }
    
    3 回复  |  直到 15 年前
        1
  •  2
  •   reko_t    15 年前

    因为您只是在删除集合中的每个元素,所以可以这样做:

        for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();itr2++) 
        {
                classA *lt=(classA*)(*itr2);
                delete lt;
        }
        li.clear(); // clear the elements
    
        2
  •  41
  •   Tadeusz Kopec for Ukraine yespbs    15 年前

    来自标准23.1.2

    插入成员不应影响迭代器和对容器的引用的有效性,而擦除成员只应使迭代器和对已擦除元素的引用失效。

    编辑

    在您的情况下,itr2在删除后无效,因此递增会导致未定义的行为。在这种情况下,您可以遵循Reko_t的建议,一般来说,您可以尝试以下方法:

    for (SETTYPE::iterator itr2=li.begin();itr2!=li.end();) 
    {
        classA *lt=(classA*)(*itr2);
        li.erase(itr2++); 
        delete lt;
    }
    

    它将增加迭代器 之前 从集合中移除它的前一个值。
    btw.itr2不因以下原因无效: delete lt; 但通过 li.erase(itr2);

        3
  •  7
  •   peterchen    15 年前

    删除操作正常。

    问题是你抹去了-因此无效- itr2 ,但将其用于循环迭代。

    第一次擦除后, ++itr2 有未定义的结果。

    我在这种情况下使用的模式是:

    while(itr2 != end())
    {
       iterator toDelete = itr2;
       ++itr2;   // increment before erasing!
       container.erase(toDelete);
    }
    

    一些非标准的stl impl具有erase返回下一个迭代器,因此可以执行以下操作:

    while(itr2 != end())
       itr2 = container.erase();
    

    不过,那不是便携式的。


    这个 set<A*,B> 不过,很奇怪——在标准IMPL中,B是比较器。