3

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

我正在尝试从字符串向量中删除第三个元素。使用函数对象的第 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.cpp -std=gnu++0x

输入: 王后 杰克 Ace Rook Knight Pawn Bishop

输出:

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

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

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

输入: 王后 杰克 Ace Rook Knight Pawn Bishop

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

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

谁能解释一下这两种行为?

4

2 回答 2

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);
     }
}
于 2013-07-27T19:38:02.790 回答
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);
..

擦除向量的第三个元素。

此致

于 2013-07-28T00:23:07.433 回答