您的位置:首页 > 其它

慎重选择删除元素的方法

2015-10-13 13:46 148 查看
一、要删除容器中中有特定值的所有对象:

(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++肯定失效;

正确的方法

for(Container<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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: