std::remove, std::remove_if
| Definiert in Header <algorithm> |
||
| (1) | ||
template< class ForwardIt, class T > ForwardIt remove( ForwardIt first, ForwardIt last, const T& value ); |
(constexpr seit C++20) (bis C++26) |
|
| template< class ForwardIt, class T = typename std::iterator_traits <ForwardIt>::value_type > |
(seit C++26) | |
| (2) | ||
| template< class ExecutionPolicy, class ForwardIt, class T > ForwardIt remove( ExecutionPolicy&& policy, |
(seit C++17) (bis C++26) |
|
| template< class ExecutionPolicy, class ForwardIt, class T = typename std::iterator_traits |
(seit C++26) | |
template< class ForwardIt, class UnaryPred > ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPred p ); |
(3) | (constexpr seit C++20) |
| template< class ExecutionPolicy, class ForwardIt, class UnaryPred > ForwardIt remove_if( ExecutionPolicy&& policy, |
(4) | (seit C++17) |
Entfernt alle Elemente, die bestimmte Kriterien erfüllen, aus dem Bereich [first, last) und gibt einen Iterator nach dem Ende des neuen Bereichs zurück.
|
std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> ist true. |
(bis C++20) |
|
std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> ist true. |
(seit C++20) |
|
Wenn der Werttyp von |
(bis C++11) |
|
Wenn der Typ von *first nicht MoveAssignable ist, ist das Verhalten undefiniert. |
(seit C++11) |
Inhalt |
[edit] Erklärung
Das Entfernen erfolgt durch Verschieben der Elemente im Bereich, so dass die Elemente, die nicht entfernt werden sollen, am Anfang des Bereichs erscheinen.
- Das Verschieben erfolgt durch Kopierzuweisung(bis C++11)Verschiebungszuweisung(seit C++11).
- Der Entfernungsvorgang ist stabil: Die relative Reihenfolge der nicht zu entfernenden Elemente bleibt erhalten.
- Die zugrunde liegende Sequenz von
[first,last)wird durch den Entfernungsvorgang nicht verkürzt. Sei result der zurückgegebene Iterator
- Alle Iteratoren in
[result,last)sind weiterhin dereferenzierbar.
- Alle Iteratoren in
|
(seit C++11) |
[edit] Parameter
| first, last | - | das Iteratorenpaar, das den Bereich der zu verarbeitenden Elemente definiert |
| value | - | der Wert der zu entfernenden Elemente |
| policy | - | die Ausführungsrichtlinie, die verwendet werden soll |
| p | - | unäres Prädikat, das true zurückgibt, wenn das Element entfernt werden soll. Der Ausdruck p(v) muss für jedes Argument |
| Typanforderungen | ||
-ForwardIt muss die Anforderungen von LegacyForwardIterator erfüllen. | ||
-UnaryPredicate muss die Anforderungen eines Prädikats erfüllen. | ||
[edit] Rückgabewert
Iterator nach dem Ende des neuen Wertebereichs (wenn dieser nicht end ist, dann zeigt er auf einen undefinierten Wert, ebenso wie Iteratoren zu allen Werten zwischen diesem Iterator und end).
[edit] Komplexität
Gegeben sei N als std::distance(first, last).
[edit] Ausnahmen
Die Überladungen mit einem Template-Parameter namens ExecutionPolicy berichten Fehler wie folgt
- Wenn die Ausführung einer Funktion, die als Teil des Algorithmus aufgerufen wird, eine Ausnahme auslöst und
ExecutionPolicyeine der Standardrichtlinien ist, wird std::terminate aufgerufen. Für jede andereExecutionPolicyist das Verhalten implementierungsabhängig. - Wenn dem Algorithmus der Speicher zur Neuzuweisung fehlt, wird std::bad_alloc ausgelöst.
[edit] Mögliche Implementierung
| 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] Hinweise
Ein Aufruf von remove wird typischerweise von einem Aufruf der erase-Mitgliedsfunktion eines Containers gefolgt, um die Elemente tatsächlich aus dem Container zu entfernen. Diese beiden Aufrufe zusammen bilden das sogenannte erase-remove-Idiom.
|
Der gleiche Effekt kann auch durch die folgenden Nicht-Member-Funktionen erzielt werden
|
(seit C++20) |
Die ähnlich benannten Memberfunktionen von Containern Member-Funktionen list::remove, list::remove_if, forward_list::remove und forward_list::remove_if löschen die entfernten Elemente.
Diese Algorithmen können nicht mit assoziativen Containern wie std::set und std::map verwendet werden, da ihre Iteratortypen nicht auf MoveAssignable-Typen dereferenzieren (die Schlüssel in diesen Containern sind nicht modifizierbar).
Die Standardbibliothek definiert auch eine Überladung von std::remove in <cstdio>, die einen const char* nimmt und zum Löschen von Dateien verwendet wird.
Da std::remove value per Referenz entgegennimmt, kann es unerwartete Ergebnisse liefern, wenn es sich um eine Referenz auf ein Element des Bereichs [first, last) handelt.
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type |
202403 |
(C++26) | Listeninitialisierung für Algorithmen (1,2) |
[edit] Beispiel
Der folgende Code entfernt alle Leerzeichen aus einem String, indem er alle Nicht-Leerzeichen nach links verschiebt und dann die überflüssigen Zeichen löscht. Dies ist ein Beispiel für das erase-remove-Idiom.
#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}})); }
Ausgabe
1) "Quick Red Dog" 2) "QuickRedDog Dog" 3) "QuickRedDog", size: 15 4) "QuickRedDog", size: 11 5) "JumpedOverALazyFox"
[edit] Defect Reports
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| LWG 283 | C++98 | T musste EqualityComparable sein, aberder Werttyp von ForwardIt ist nicht immer T |
erforderte, dass der Werttyp von ForwardItstattdessen CopyAssignable ist |
[edit] Siehe auch
| Kopiert einen Bereich von Elementen und lässt diejenigen aus, die bestimmte Kriterien erfüllen (Funktionstemplate) | |
| Entfernt aufeinanderfolgende doppelte Elemente in einem Bereich (Funktionstemplate) | |
| (C++20)(C++20) |
entfernt Elemente, die bestimmte Kriterien erfüllen (Algorithmus-Funktionsobjekt) |