钻个容器erase的牛角尖(欢迎指导)

camelisi 2013-02-19 04:18:12
今日工作遇到一个问题,以前一直使用以下方法中的第一种方式,连续删除关联容器元素,今日突然得见第二种方式,被告知第一种在erase的后迭代器有可能失效,此时迭代器再自加则会崩溃,貌似有些道理,所以小弟在此请教下,求解迷津。


//第一种
AssocContainer<int> c;
...
for (AssocContainer<int>::iterator i = c.begin(); i != c.end();)
{
if (badValue(*i))
c.erase(i++); // 对于坏的值,把当前的
else
++i; // i传给erase,然后
} // 作为副作用增加i;对于好的值,只增加i

//第二种
AssocContainer<int> c;
...
for (AssocContainer<int>::iterator i = c.begin(); i != c.end();)
{
AssocContainer<int>::iterator iTemp = i++;
if (badValue(*i))
c.erase(i); // 对于坏的值,把当前的
}
...全文
349 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2013-02-20
  • 打赏
  • 举报
回复
对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行!
rocktyt 2013-02-20
  • 打赏
  • 举报
回复
[quote=引用 6 楼 camelisi 的回复:] c.erase(iter++); // 我同事的意思是,这里i是先被erase的, //关联容器这个i是不是在erase之 //后被释放呢?然后才执行的自增,如果i已经失效, //则有可能导致崩溃,如果 //不崩溃,则是没失效,具体估计就得开代码实现了 [quote] 不知道是你写错了还是你和你同事根本没理解后置++的含义 iter++是对iter自增然后返回一个自增前的值,是先自增然后再erase的 erase后指向被删除的结点的迭代器自然是失效的,但是其他迭代器都是有效的
sumos 2013-02-20
  • 打赏
  • 举报
回复
vector<int> vec; for(vector<int>::iterator iter = vec.begin(); iter != vec.end();) { if(bad) iter = vec.erase(iter); else ++iter; }
iamnobody 2013-02-20
  • 打赏
  • 举报
回复
引用 6 楼 camelisi 的回复:
第二种写错了。。粗心了 C/C++ code?1234567891011121314151617181920212223242526//第一种 AssocContainer<int> c; ... for (AssocContainer<int>::iterator iter = c.begin(); iter != c.end();) { if (b……
第一种, I 会先自增然后再进入erase函数. 没有问题.
camelisi 2013-02-20
  • 打赏
  • 举报
回复
第二种写错了。。粗心了

//第一种 
AssocContainer<int> c; 
... 
for (AssocContainer<int>::iterator iter = c.begin(); iter != c.end();)  
{     
    if (badValue(*iter)) 
        c.erase(iter++);       // 我同事的意思是,这里i是先被erase的,
                               //关联容器这个i是不是在erase之
                               //后被释放呢?然后才执行的自增,如果i已经失效,
                               //则有可能导致崩溃,如果
                               //不崩溃,则是没失效,具体估计就得开代码实现了      
     else       
        ++i;            
}   


//第二种 
AssocContainer<int> c;                      
// 我这里就表示是关联容器了,顺序是用erase的 返回值
... 
for (AssocContainer<int>::iterator iter = c.begin(); iter != c.end();)  
{     
    AssocContainer<int>::iterator  itTemp = iter++;  // iter与此处完成自增
    if (badValue(*itTemp ))        
        c.erase(itTemp );                   // 这里的i应该是itTemp 
}                
camelisi 2013-02-20
  • 打赏
  • 举报
回复
结贴了,答案是对于关联容器来说两者都可以,看了下Effective STL以及SGI STL里面相关的容器后置++实现,erase(i++)这个,i++之后返回了i的迭代器,这个给erase删除,erase执行之前,i已经自加了
taodm 2013-02-20
  • 打赏
  • 举报
回复
楼主,别钻了,买本effective stl认真啃啃 你现在问的,和即将问的,上面都有现成答案了。
billzheng 2013-02-20
  • 打赏
  • 举报
回复
引用 16 楼 ajey2005 的回复:
标准的STL关联式容器包括:set、multiset、map、multimap。 vector list什么的不是啊童鞋们。 另外删除关联容器元素的时候其他元素的迭代器不会受影响,这两种方法都可以的。
最后一句话错了,应该使用std::remove_if. 如果你的map/set 有1百万单元, 你全部循环一遍??
无猫皆笼 2013-02-20
  • 打赏
  • 举报
回复
标准的STL关联式容器包括:set、multiset、map、multimap。 vector list什么的不是啊童鞋们。 另外删除关联容器元素的时候其他元素的迭代器不会受影响,这两种方法都可以的。
teamworkpmy 2013-02-20
  • 打赏
  • 举报
回复
不太清楚关联容器以及erase的内部实现,第二种较第一种更靠谱一点。
billzheng 2013-02-20
  • 打赏
  • 举报
回复
引用 13 楼 Dnkuni 的回复:
两种写法本质是一样的。用在list类型的没有问题,vector类型的就不行了。 一般用remove_if比较好 C/C++ code?12AssocContainer<int>::iterator remove_end = remove_if(c.begin(), c.end(), [](int elm){return badValue(elm);});c.erase……
He is talking about associative container, you don't need to use remove erase idiom.
Dnkuni 2013-02-20
  • 打赏
  • 举报
回复
两种写法本质是一样的。用在list类型的没有问题,vector类型的就不行了。 一般用remove_if比较好

AssocContainer<int>::iterator remove_end = remove_if(c.begin(), c.end(), [](int elm){return badValue(elm);});
c.erase(remove_end, c.end());
billzheng 2013-02-20
  • 打赏
  • 举报
回复
Should use std::remove_if algorithm easily instead of looping through the entire container. As Associated container is sorted already, isn't it faster by using std::remove_if? Also it has less chance to have invalid iterator because you don't use it explicitly. AssocContainer<int> c; std::remove_if(c.begin(), c.end(), [](int i){ return badValue(i); });
mymtom 2013-02-20
  • 打赏
  • 举报
回复
两种方法都没有问题啊。 但是个人习惯用8楼的方法
引用 8 楼 zhoujielunzhimi 的回复:
vector<int> vec; for(vector<int>::iterator iter = vec.begin(); iter != vec.end();) { if(bad) iter = vec.erase(iter); else ++iter; }
  • 打赏
  • 举报
回复
第一个是正确的.
翅膀又硬了 2013-02-19
  • 打赏
  • 举报
回复
iterator i 定义i为迭代器,看着真别扭
rocktyt 2013-02-19
  • 打赏
  • 举报
回复
先不说第一种和第二种erase的对象根本就不一样 你这2种方法根本就没有本质上的差别吧,erase完成后的i都是erase前的i自增后的结果 这段代码应该是effective stl上的,AssocContainer是指某一种关联容器,关联容器是有保证删除某个元素后迭代器不失效的 而对于序列容器,应该用1楼的方法,而不是lz的方法2,而这也是在effective stl里有写的
luciferisnotsatan 2013-02-19
  • 打赏
  • 举报
回复
迭代器是否会失效,得看这个迭代器(容器)的说明文档。这个AssocContainer是什么东西? 一般erase后会失效的,那么erase会返回一个有效的,指向下一个元素的迭代器。
FingerStyle 2013-02-19
  • 打赏
  • 举报
回复
iter = c.earse(..); 可以通过earse的返回值保存下个有效的iter. 或者用erase(remove....) 惯用方法.

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧