web-dev-qa-db-ja.com

消去-remove_ifイディオムの使用

std::vector<std::pair<int,Direction>>があるとしましょう。

私はerase-remove_ifイディオムを使用して、ベクターからペアを削除しようとしています。

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }));

.first値が4に設定されているすべてのペアを削除したいと思います。

私の例では、ペアがあります。

- 4, Up
- 4, Down
- 2, Up
- 6, Up

ただし、erase-remove_ifを実行すると、次のようになります。

- 2, Up
- 6, Up
- 6, Up

私はここで何が間違っているのですか?

12
omegasbk

正しいコードは次のとおりです。

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool 
                                       { return stopPoint.first == 4; }), 
                 stopPoints.end());

単一の要素だけでなく、std::remove_ifから返されたイテレータからベクトルの終わりまでの範囲を削除する必要があります。

「なぜ?」

  • std::remove_ifは、配置するためにベクトル内で要素を交換しますコンテナの先頭に向かって述語に一致しないすべての要素

    • 次に最初の述語一致要素を指すイテレータを返します

    • std::vector::eraseは、述語に一致するすべての要素を削除するために、返されたイテレータからベクトルの終わりまでの範囲を消去する必要があります。


詳細情報:消去-削除イディオム(ウィキペディア)

20
Vittorio Romeo

メソッド _std::vector::erase_ には2つのオーバーロードがあります。

_iterator erase( const_iterator pos );
iterator erase( const_iterator first, const_iterator last );
_

最初の要素はposの要素のみを削除し、2番目の要素は範囲_[first, last)_を削除します。

呼び出しでlastイテレータを忘れたため、最初のバージョンは過負荷解決によって選択され、_std::remove_if_によって最後にシフトされた最初のペアのみが削除されます。これを行う必要があります:

_stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }), 
                 stopPoints.end());
_

erase-removeイディオムは次のように機能します。ベクトル_{2, 4, 3, 6, 4}_があり、_4_を削除するとします。

_std::vector<int> vec{2, 4, 3, 6, 4};
auto it = std::remove(vec.begin(), vec.end(), 4);
_

最後に「削除された」値を置くことにより、ベクトルを_{2, 3, 6, A, B}_に変換します(最後の値ABは指定されていません(値がmoved)、これが、例で_6_を取得し、イテレータをA(最初の「削除済み」)に返す理由です。 "値)。

もしあなたがそうするなら:

_vec.erase(it)
_

_std::vector::erase_の最初のオーバーロードが選択され、itの値のみが削除されます。これはAであり、_{2, 3, 6, B}_を取得します。

2番目の引数を追加することによって:

_vec.erase(it, vec.end())
_

2番目のオーバーロードが選択され、itvec.end()の間の値が消去されるため、ABの両方が消去されます。

7
Holt