3

ベクトルから消去すると、ラムダ関数と関数オブジェクトで異なる結果が得られます。

文字列のベクトルから 3 番目の要素を削除しようとしています。関数オブジェクトでは 3 番目と 6 番目の要素が削除されますが、ラムダ バージョンではコードが期待どおりの結果をもたらします。

次のコードを試しました:

#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

入力: キング クイーン ジャック エース ルーク ナイト ポーン ビショップ

出力:

S : キング クイーン ジャック エース ルーク ナイト ポーン ビショップ

現在、S には : キング クイーン エース ルーク ポーン ビショップ//間違った結果 3 と 6 番目の要素が削除されました。

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

入力: キング クイーン ジャック エース ルーク ナイト ポーン ビショップ

S : キング クイーン ジャック エース ルーク ナイト ポーン ビショップ

現在 S には : キング クイーン エース ルーク ナイト ポーン ビショップ // 正しい結果が含まれています

誰でもこれら2つの動作を説明できますか?

4

2 に答える 2

3

あなたはremove_if実装の犠牲者です。Josuttis の The C++ Standard Library では、これについて詳しく説明しています。

要約は次のとおりです。

3 番目と 6 番目の要素はremove_if、処理中に述語を内部的にコピーするため、ラムダ バージョンなしでは削除されます。

find_if内部的に使用して、削除する必要がある要素を見つけます。その後、アルゴリズムは述語のコピーを使用して残りの要素を処理します。remove_if_copy

ラムダの場合、引数を参照渡ししているため、内部で使用されるラムダオブジェクト 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 効果: 範囲 [first,last) 内の反復子 i によって参照されるすべての要素を削除します。これらの要素について、対応する条件は次のとおりです: *i == value, pred(*i) != false.

3 戻り値: 結果の範囲の終わり。

4 備考: 安定 (17.6.5.7)。

5 複雑さ: 対応する述語の正確な最後 - 最初の適用。

6 注: ret が戻り値である範囲 [ret,last) 内の各要素は、有効ですが指定されていない状態を持ちます。なぜなら、アルゴリズムは、元々その範囲内にあった要素から移動することによって要素を削除できるからです。

したがって、ベクトルの要素と同じ順序で述語が使用されると想定しないでください。

最後に、簡単に書くことができます

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

ベクトルの 3 番目の要素を消去します。

よろしくお願いします

于 2013-07-28T00:23:07.433 に答える