最近有用到STL 的泛型算法remove_if,反复看了MSDN好几遍,硬是没理解这个函数的真正含义,好吧,其实我的英语老师是教体育的 - -! 后来看了STL源码 ,算是发现其中的奥秘了,这里写个笔记算是给自己加深一点 印象吧,下面我任然使用MSDN的范例做说明。
int greater6 ( int value ) { return value >6; } int _tmain(int argc, _TCHAR* argv[]) { int Array[12] = {1,7,9,2,0,7,7,3,4,6,8,5}; vector <int> v1; vector <int>::iterator Iter1, Iter2, new_end; for(int i=0;i<12;i++) v1.push_back(Array[i]); cout << "Vector v1 is \n( " ; for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ ) cout << *Iter1 << " "; cout << ")." << endl; new_end = remove_if (v1.begin( ), v1.end( ), greater6 ); cout << "Vector v1 with elements satisfying greater6 removed is\n( " ; for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ ) cout << *Iter1 << " "; cout << ")." << endl; // To change the sequence size, use erase v1.erase (new_end, v1.end( ) ); cout << "Vector v1 resized elements satisfying greater6 removed is\n( " ; for ( Iter1 = v1.begin( ) ; Iter1 != v1.end( ) ; Iter1++ ) cout << *Iter1 << " "; cout << ")." << endl; }
remove_if有三个参数,前2个参数是传入需要操作的迭代器区间,参数3是一个函数指针,他的作用是作为移除哪些元素的赛选条件。查看 remove_if 的源码得知 它首先调用了一个 find_if 算法找到满足移除条件的第一个元素,并返回该元素的迭代器.然后调用unchecked_remove_copy_if算法函数,该函数和remove_copy_if类似,实际他内部也是调用的remove_copy_if
下面是伪代码:
remove_if(itr_begin,itr_end,funPtr) { itr_find = find_if(itr_begin,itr_end,funPtr); itr_begin = itr_find; unchecked_remove_copy_if(++itr_begin,itr_end,itr_begin,funPtr); }
下面给出了remove_copy_if的伪代码实现
remove_copy_if(_First,_Last,_Dest,funPtr) { for (; _First != _Last; ++_First) { if (!funPtr(*_First)) *_Dest++ = *_First; } return (_Dest); }
从源码实现的可以看得出来, 从第一个满足移除条件的后一个元素开始向容器尾部遍历, 当检查到一个元素不满足移除条件就把他和第一个满足条件的元素替换.
下面是示例代码中remove_copy_if的每一次循环结果:
(貌似排版有点问题,在执行第一次循环的时候迭代器d是指向元素7,f指向元素9)
1 1, 7, 9, 2, 0, 7, 7, 3, 4, 6, 8, 5 end d f 2 1, 2, 9, 2, 0, 7, 7, 3, 4, 6, 8, 5 end d f 3 1, 2, 0, 2, 0, 7, 7, 3, 4, 6, 8, 5 end d f 4 1, 2, 0, 2, 0, 7, 7, 3, 4, 6, 8, 5 end d f 5 1, 2, 0, 2, 0, 7, 7, 3, 4, 6, 8, 5 end d f 6 1, 2, 0, 2, 0, 7, 7, 3, 4, 6, 8, 5 end d f 7 1, 2, 0, 3, 0, 7, 7, 3, 4, 6, 8, 5 end d f 8 1, 2, 0, 3, 4, 7, 7, 3, 4, 6, 8, 5 end d f 9 1, 2, 0, 3, 4, 6, 7, 3, 4, 6, 8, 5 end d f 10 1, 2, 0, 3, 4, 6, 7, 3, 4, 6, 8, 5 end d f 11 1, 2, 0, 3, 4, 6, 5, 3, 4, 6, 8, 5 end d f
11次循环遍历结束,现在容器v1中的元素就是第11步的元素顺序。1, 2, 0, 3, 4, 6, 5 之后的元素是我在没看源代码之前所疑惑的地方,了解源码后就清楚知道后面的元素(3, 4, 6, 8, 5)是从何而来的了。remove_if 不会改变容器的size大小,他的返回值是一个迭代器,指向所有满足移除条件元素中的第一个元素,在这里也就是第二个3,一般remove_if 是和 容器的erase方法一起使用的,所以在我调用 v1.erase(newEnd,v1.end)方法后v1剩下的元素排列是: 1, 2, 0, 3, 4, 6, 5。
和remove_if算法类似的函数还有:
remove 方法第三个参数传入的是一个常量,表示移除指定的这个常量值
remove_copy_if 方法可以把移除后的结果通过第三个参数传入到另外一个的容器中,当然这个容器一定要足够大容纳下来容纳下元素,否则后果很严重。