慎重选择删除元素的方法

来源:互联网 发布:linux shell 管道 编辑:程序博客网 时间:2024/04/28 09:46

一、要删除容器中中有特定值的所有对象:

(1)如果容器是vector、string或deque,则使用erase-remove习惯用法:

c.erase(remove(c.begin(),c.end(),1963),c.end());

(2)如果容器是list,则使用list::remove,此时remove是其成员函数:

c.remove(1963);

(3)如果容器是一个标准关联容器,则使用它的erase成员函数,不能使用remove函数,因为关联容器不含有remove函数:

c.erase(1963);

二、要删除容器中满足特定判别条件的所有对象:

删除判使bool badValue(int);返回true的每一个对象

(1)如果容器是vector、list或deque,则使用erase-remove_if习惯用法:

c.erase(remove_if(c.begin(),c.end(),badValue),c.end());

(2)如果容器是list,则使用list::remove_if:

c.remove_if(c.begin(),c.end(),badValue);

(3)如果容器是标准关联容器

方法一:简单但效率稍低,利用remove_copy_if函数把我们需要的值赋值到另外一个容器中,然后用swap交换这两个容器的内容

Container<int> c;//c现在是一个关联容器Container<int> goodValues;//保存不被删除值的临时容器remove_copy_if(c.begin(),c.end(),inserter(goodValues,goodValues.end()),badValue);//把不被删除的值从c复制到goodValues中c.swap(goodValues);//交换c和goodValues的内容

方法二:关联容器没有提供类似remove_if的成员函数,则需要写一个循环遍历c中的元素,并个遍历过程中删除元素

假设我们这么写

//错误写法for(Container<int>::iterator i=c.begin();i!=c.end();++i){if(badValue(*i)) c.erase(i);//迭代器失效}

当容器内的一个元素被删除之时,指向该元素的所有迭代器都将变得无效,一旦c.erase(i)返回后,i就成为无效值,对于这个循环,那么i++肯定失效;

正确的方法

forContainer<int>::iterator i=c.begin();i!=c.end();){//for循环第三部分是空的if(badValue(*i)) c.erase(i++);//else++i;}

这样,我们把旧的i传给erase,但在erase开始执行前也递增了i


三、在删除每次元素时,都向日志文件写一条信息:

(1)对于关联容器十分简单,仅只需做一点点修改

ofstream logFile;//要写入的日志文件Container<int> c;for(Container<int>::iterator i=c.begin();i!=c.end();)//同上{if(badValue(*i)){logFile<<"Erasing"<<*i<<'\n';//写入日志文件c.erase(i++);//删除元素}else{++i;}}

如果容器是一个标准序列容器,我们不能再用erase_remove_if的习惯用法。且不能使用刚刚关联容器的循环设计,因为对于序列容器,调用erase不仅会使指向被删除元素的迭代器无效,也会使被删除元素之后的所有迭代器失效,因此采用++i、i++都无济于事。

(2)对于序列容器,我们需要采取不同的策略,尤其要利用其返回值。一旦erase完成,它是指向紧随被删除元素的下一个元素的所有迭代器,则写一个循环来遍历容器中的元素,记住每次调用erase时,要用它的返回值更新迭代器。

for(Container<int>::iterator i=c.begin();i!=c.end();){if(badValue(*i)){LogFile<<"Erasing"<<*i<<'\n';i=c.erase(i);}else{++i;}}

(3)对于list容器一般采用和vector、string、deque相同的方式


参考:Effective Stl

0 0
原创粉丝点击