2009-10-28 56 views
10

中擦除()后,迭代器的有效性在std :: set invalidate iterator中擦除调用吗?正如我从最后一行5号以下完成的..? 如果是有什么更好的方式来擦除集的所有元素在std :: set

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 ? 
     } 
    } 
} 
+2

typedef std :: set SETTYPE; 我不知道你为什么要给StructB作为std :: set的第二个模板参数。 std :: set只保存一个值(没有与map一起使用的键),第二个模板参数用于为集合提供比较函数(默认为std :: less) – 2009-10-28 11:12:43

回答

2

既然你是刚刚显然删除集的每一个元素,你可以只是做:

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

thx reko_t,这解决了我的问题问题 – Satbir 2009-10-28 11:32:37

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

这将增加迭代之前删除它从组先前值。
顺便说一句。 itr2没有被delete lt;失效,但是被li.erase(itr2);

+3

由于这回答我的谷歌的“设置清除无效迭代器”,这也是我最喜欢的回答 – Chance 2012-04-23 17:02:08

+0

我最喜欢的答案! – Micka 2014-06-30 08:09:27

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是比较。