午夜稻草人

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

假定你有一个标准STL容器,c,容纳int,

1 Container<int> c;

而你想把c中所有值为1963的对象都去掉。令人吃惊的是,完成这项任务的方法因不同的容器类型而不同:没有一种方法是通用的。

如果你有一个连续内存容器(vector、deque或string),最好的方法是erase-remove惯用法:

1 c.erase(remove(c.begin(), c.end(), 1963), // 当c是vector、string
2 c.end()); // 或deque时,
3 // erase-remove惯用法
4 // 是去除特定值的元素
5 // 的最佳方法

这方法也适合于list,但是,list的成员函数remove更高效:

1 c.remove(1963); // 当c是list时,
2 // remove成员函数是去除
3 // 特定值的元素的最佳方法

当c是标准关联容器(即,set、multiset、map或multimap)时,使用任何叫做remove的东西都是完全错误的。这样的容器没有叫做remove的成员函数,而且使用remove算法可能覆盖容器值,潜在地破坏容器。

对于关联容器,解决问题的适当方法是调用erase:

1 c.erase(1963); // 当c是标准关联容器时
2 // erase成员函数是去除
3 // 特定值的元素的最佳方法

这不仅是正确的,而且很高效,只花费对数时间。

如果是符合某个判断式的条件

1 bool badValue(int x); // 返回x是否是“bad”

对于序列容器(vector、string、deque和list),我们要做的只是把每个remove替换为remove_if,然后就完成了:

1 c.erase(remove_if(c.begin(), c.end(), badValue), // 当c是vector、string
2 c.end()); // 或deque时这是去掉
3 // badValue返回真
4 // 的对象的最佳方法
5 c.remove_if(badValue); // 当c是list时这是去掉
6 // badValue返回真
7 // 的对象的最佳方法

关联容器:

 1 AssocContainer<int> c;
 2 ...
 3 for (AssocContainer<int>::iterator i = c.begin(); // for循环的第三部分
 4 i != c.end(); // 是空的;i现在在下面
 5 /*nothing*/ ){ // 自增
 6 if (badValue(*i)) c.erase(i++); // 对于坏的值,把当前的
 7 else ++i; // i传给erase,然后
 8 } // 作为副作用增加i;
 9 // 对于好的值,
10 // 只增加i

现在让我们进一步修改该问题。不仅删除badValue返回真的每个元素,而且每当一个元素被删掉时,我们也想把一条消息写到日志文件中。

对于关联容器,这说多容易就有多容易,因为只需要对我们刚才开发的循环做一个微不足道的修改就行了:

 1 ofstream logFile; // 要写入的日志文件
 2 AssocContainer<int> c;
 3 ...
 4 for (AssocContainer<int>::iterator i = c.begin(); // 循环条件和前面一样
 5 i !=c.end();){
 6 if (badValue(*i)){
 7 logFile << "Erasing " << *i <<'\n'; // 写日志文件
 8 c.erase(i++); // 删除元素
 9 }
10 else ++i;
11 }

我们必须对vector、string和deque采用不同的战略。特别是,我们必须利用erase的返回值。那个返回值正是我们需要的:一旦删除完成,它就是指向紧接在被删元素之后的元素的有效迭代器。换句话说,我们这么写:

1 for (SeqContainer<int>::iterator i = c.begin();
2 i != c.end();){
3 if (badValue(*i)){
4 logFile << "Erasing " << *i << '\n';
5 i = c.erase(i); // 通过把erase的返回值
6 } // 赋给i来保持i有效
7 else
8 ++i;
9 }

 

posted on 2013-04-30 09:57  午夜稻草人  阅读(689)  评论(0编辑  收藏  举报