std::remove, std::remove_if
| ヘッダー <algorithm> で定義 |
||
| (1) | ||
template< class ForwardIt, class T > ForwardIt remove( ForwardIt first, ForwardIt last, const T& value ); |
(C++20 以降 constexpr) (C++26まで) |
|
| template< class ForwardIt, class T = typename std::iterator_traits <ForwardIt>::value_type > |
(C++26以降) | |
| (2) | ||
| template< class ExecutionPolicy, class ForwardIt, class T > ForwardIt remove( ExecutionPolicy&& policy, |
(C++17以降) (C++26まで) |
|
| template< class ExecutionPolicy, class ForwardIt, class T = typename std::iterator_traits |
(C++26以降) | |
template< class ForwardIt, class UnaryPred > ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPred p ); |
(3) | (C++20 以降 constexpr) |
| template< class ExecutionPolicy, class ForwardIt, class UnaryPred > ForwardIt remove_if( ExecutionPolicy&& policy, |
(4) | (C++17以降) |
指定された条件を満たす要素を範囲 [first, last) から削除し、範囲の新しい終端を示すイテレータを返します。
|
std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> が true である。 |
(C++20まで) |
|
std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> は true です。 |
(C++20以降) |
|
|
(C++11まで) |
|
*first の型が MoveAssignable でない場合、動作は未定義です。 |
(C++11以降) |
目次 |
[edit] 説明
削除は、削除されない要素が範囲の先頭に現れるように、範囲内の要素をシフトすることによって行われます。
- シフトは コピー代入(C++11 まで)ムーブ代入(C++11 以降) によって行われます。
- 削除操作は安定です。削除されない要素の相対順序は変更されません。
[first,last)の基となるシーケンスは、削除操作によって短縮されません。返されるイテレータを result とすると
[result,last)のすべてのイテレータは、依然として デリファレンス可能です。
|
(C++11以降) |
[edit] パラメータ
| first, last | - | 処理する要素の 範囲 を定義するイテレータのペア |
| value | - | 削除する要素の値 |
| policy | - | 使用する 実行ポリシー |
| p | - | 要素を削除すべき場合に true を返す単項述語。
|
| 型要件 | ||
-ForwardIt は LegacyForwardIterator の要件を満たさなければなりません。 | ||
-UnaryPredicate は Predicate の要件を満たさなければなりません。 | ||
[edit] 戻り値
新しい値の範囲を示す終端イテレータ(これが end でない場合、未指定の値を示し、このイテレータと end の間の値に対するイテレータも同様です)。
[edit] 計算量
std::distance(first, last) を N とする
[edit] 例外
ExecutionPolicy というテンプレートパラメータを持つオーバーロードは、次のようにエラーを報告します。
- アルゴリズムの一部として呼び出された関数の実行が例外をスローし、
ExecutionPolicyが 標準ポリシー のいずれかである場合、std::terminate が呼び出されます。その他のExecutionPolicyの場合、動作は実装定義です。 - アルゴリズムがメモリの割り当てに失敗した場合、std::bad_alloc がスローされます。
[edit] 実装例
| remove (1) |
|---|
template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type> ForwardIt remove(ForwardIt first, ForwardIt last, const T& value) { first = std::find(first, last, value); if (first != last) for (ForwardIt i = first; ++i != last;) if (!(*i == value)) *first++ = std::move(*i); return first; } |
| remove_if (3) |
template<class ForwardIt, class UnaryPred> ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPred p) { first = std::find_if(first, last, p); if (first != last) for (ForwardIt i = first; ++i != last;) if (!p(*i)) *first++ = std::move(*i); return first; } |
[edit] 注記
remove の呼び出しの後には、通常、コンテナから要素を実際に削除するためのコンテナの erase メンバ関数の呼び出しが続きます。この 2 つの呼び出しを組み合わせたものが、いわゆる erase-remove イディオムです。
|
同様の効果は、次の非メンバ関数でも達成できます。
|
(C++20以降) |
同様の名前を持つコンテナの メンバ関数である list::remove、list::remove_if、forward_list::remove、および forward_list::remove_if は、削除された要素を削除します。
これらのアルゴリズムは、std::set や std::map のような連想コンテナには使用できません。これは、これらのコンテナのイテレータ型が MoveAssignable 型をデリファレンスしないためです(これらのコンテナのキーは変更できません)。
標準ライブラリは、<cstdio> に std::remove のオーバーロードも定義しています。これは const char* を取り、ファイルの削除に使用されます。
std::remove は value を参照で受け取るため、それが範囲 [first, last) の要素への参照である場合、予期しない動作を引き起こす可能性があります。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type |
202403 |
(C++26) | アルゴリズム (1,2) のためのリスト初期化 |
[edit] 例
次のコードは、文字列からすべてのスペースを削除します。これは、スペース以外のすべての文字を左にシフトしてから、余分な文字を削除することによって行われます。これは erase-remove イディオムの例です。
#include <algorithm> #include <cassert> #include <cctype> #include <complex> #include <iomanip> #include <iostream> #include <string> #include <string_view> #include <vector> int main() { std::string str1{"Quick Red Dog"}; std::cout << "1) " << std::quoted(str1) << '\n'; const auto noSpaceEnd = std::remove(str1.begin(), str1.end(), ' '); std::cout << "2) " << std::quoted(str1) << '\n'; // The spaces are removed from the string only logically. // Note, we use view, the original string is still not shrunk: std::cout << "3) " << std::quoted(std::string_view(str1.begin(), noSpaceEnd)) << ", size: " << str1.size() << '\n'; str1.erase(noSpaceEnd, str1.end()); // The spaces are removed from the string physically. std::cout << "4) " << std::quoted(str1) << ", size: " << str1.size() << '\n'; std::string str2 = "Jumped\n Over\tA\vLazy \t Fox\r\n"; str2.erase(std::remove_if(str2.begin(), str2.end(), [](unsigned char x) { return std::isspace(x); }), str2.end()); std::cout << "5) " << std::quoted(str2) << '\n'; std::vector<std::complex<double>> nums{{2, 2}, {1, 3}, {4, 8}}; #ifdef __cpp_lib_algorithm_default_value_type nums.erase(std::remove(nums.begin(), nums.end(), {1, 3}), nums.end()); #else nums.erase(std::remove(nums.begin(), nums.end(), std::complex<double>{1, 3}), nums.end()); #endif assert((nums == std::vector<std::complex<double>>{{2, 2}, {4, 8}})); }
出力
1) "Quick Red Dog" 2) "QuickRedDog Dog" 3) "QuickRedDog", size: 15 4) "QuickRedDog", size: 11 5) "JumpedOverALazyFox"
[edit] 不具合報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| LWG 283 | C++98 | T は EqualityComparable であることが求められていましたが、ForwardIt の値の型は常に T ではない |
ForwardIt の値の型が代わりに CopyAssignable である必要がある |
[edit] 関連項目
| 特定の基準を満たす要素を除外して範囲をコピーする (関数テンプレート) | |
| 範囲内の連続する重複要素を削除する (関数テンプレート) | |
| (C++20)(C++20) |
特定の基準を満たす要素を削除する (アルゴリズム関数オブジェクト) |