在std :: set中擦除()之后的迭代器有效性

时间:2009-10-28 11:07:39

标签: c++ stl set

在std :: set中使用erase iterator擦除调用吗?正如我在最后一行5号以下所做的那样..? 如果是,那么从集合

中删除所有元素的更好方法是什么
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 个答案:

答案 0 :(得分:41)

从标准23.1.2

  

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

修改

在你的情况下,itr2在擦除后失效,因此递增它会导致未定义的行为。在这种情况下,您可以关注reko_t建议,一般情况下,您可以尝试:

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

将增加迭代器之前从set中删除之前的值 BTW。 itr2不会被delete lt;无效,而是li.erase(itr2);

答案 1 :(得分:7)

删除正常。

问题是你擦除 - 从而使itr2无效,但是将它用于循环迭代。

i.a.w。在第一次擦除之后,++itr2具有未定义的结果。

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

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

一些非标准的STL impls有擦除返回下一个迭代器,所以你可以这样做:

while(itr2 != end())
   itr2 = container.erase();
但是,这不是便携式的。


set<A*,B> 很奇怪 - 但在标准的impl中,B将是比较器。

答案 2 :(得分:2)

由于你只是显然删除了集合中的每个元素,你可以这样做:

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