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
私はここで何が間違っているのですか?
正しいコードは次のとおりです。
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
は、述語に一致するすべての要素を削除するために、返されたイテレータからベクトルの終わりまでの範囲を消去する必要があります。
詳細情報:消去-削除イディオム(ウィキペディア) 。
メソッド _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}
_に変換します(最後の値A
とB
は指定されていません(値がmoved)、これが、例で_6
_を取得し、イテレータをA
(最初の「削除済み」)に返す理由です。 "値)。
もしあなたがそうするなら:
_vec.erase(it)
_
_std::vector::erase
_の最初のオーバーロードが選択され、it
の値のみが削除されます。これはA
であり、_{2, 3, 6, B}
_を取得します。
2番目の引数を追加することによって:
_vec.erase(it, vec.end())
_
2番目のオーバーロードが選択され、it
とvec.end()
の間の値が消去されるため、A
とB
の両方が消去されます。