矢量擦除给出了意外的结果

时间:2013-07-27 19:31:36

标签: algorithm c++11 stl

从矢量中删除,使用lambda函数和函数对象给出不同的结果。

我正在尝试从字符串向量中删除第3个元素。 使用函数对象第3和第6个元素被删除但是使用lambda版本代码会给出预期的结果。

我尝试了以下代码:

#include <iostream>
#include<algorithm>
#include<iterator>
#include<vector>

using namespace std;

int main()
{

vector<string> s;

copy(istream_iterator<string>(cin),
    istream_iterator<string>(),
    back_inserter(s));

    cout<<"S contains :"<<endl;
    for(auto x:s)
        cout<<x<<" ";
    cout<<endl;

#ifndef USE_LAMBDA    

struct Word_No{
int word_ith;
int word_count;

Word_No(int x)  :word_ith(x),word_count(0){}

bool operator () (string){
return ++word_count == word_ith;
}
};
//3rd Element remove
    s.erase(remove_if(s.begin(),s.end(),Word_No(3)),s.end());
#else
    int count =0;
    s.erase(remove_if(s.begin(),
                      s.end(),
                      [&count](string){
                         return ++count ==3; //3rd Element Remove
                            }),
                      s.end());
#endif

    cout<<"Now S contains :"<<endl;
    for(auto x:s)
        cout<<x<<" ";
}

结果:

  

g ++ -o test test.cpp -std = gnu ++ 0x

     

输入:King Queen Jack Ace Rook   骑士典当主教

     

输出:

     

S包含:King Queen Jack Ace Rook Knight Pawn Bishop

     

现在S包含:King Queen Ace Rook Pawn Bishop //错误的结果3和6元素被删除。

     

g ++ -o test test.cpp -std = gnu ++ 0x -DUSE_LAMBDA

     

输入:King Queen Jack Ace Rook Knight Pawn Bishop

     

S包含:King Queen Jack Ace Rook Knight Pawn Bishop

     

现在S包含:King Queen Ace Rook Knight Pawn Bishop //正确的结果

有人可以解释这两种行为吗?

2 个答案:

答案 0 :(得分:3)

你是remove_if实施的受害者,Josuttis的C ++标准库详细描述了这一点。

摘要是:

第3和第6个元素在没有lambda版本时被删除,因为remove_if在处理期间在内部复制谓词。

它在内部使用find_if来查找应该删除的元素。 稍后,该算法使用谓词的副本来处理剩余的元素(如果有的话),使用remove_if_copy

对于lambda,当您通过引用传递参数时,lambda对象在内部使用 remove_if分享相同的州

这是remove_if

的近似实现
template<typename FwdItr, typename Pred>
FwdItr std::remove_if(FwdItr b, FwdItr e, Pred f)
{
    s = find_if(b,e,f);
    if(s==e)
        return b;
    else
     {
        FwdItr temp = b;
        return remove_copy_if(++temp, e, b, f);
     }
}

答案 1 :(得分:2)

标准定义并未说明此函数将按特定顺序使用谓词,它所说的是:

  

1要求:* first的类型应满足MoveAssignable   要求(表22)。

     

2效果:消除迭代器i引用的所有元素   范围[first,last)以下对应的范围   条件成立:* i == value,pred(* i)!= false。

     

3返回:结果范围的结束。

     

4备注:稳定(17.6.5.7)。

     

5复杂性:完全持续 - 相应的第一个应用程序   谓词。

     

6注意:范围[ret,last]中的每个元素,其中ret是   返回值,具有有效但未指定的状态,因为   算法可以通过从元素移动来消除元素   最初在那个范围内。

因此,您不应该假设谓词的使用顺序与矢量元素的顺序相同。

最后,你可以简单地写

..
s.erase(s.begin()+2);
..

删除矢量的第三个元素。

最好的问候