2016-08-08 22 views
1

Wird std :: remove_if immer das Prädikat für jedes Element in der Reihenfolge aufrufen (gemäß der Reihenfolge des Iterators) oder könnte es als nicht in Ordnung bezeichnet werden?Ist std :: remove_if garantiert Prädikat in Reihenfolge zu rufen?

ist hier ein Spielzeug Beispiel dafür, was Ich mag zu tun wäre:

void processVector(std::vector<int> values) 
{ 
    values.erase(std::remove_if(values.begin(), values.end(), [](int v) 
    { 
     if (v % 2 == 0) 
     { 
      std::cout << v << "\n"; 
      return true; 
     } 
     return false; 
    })); 
} 

Ich brauche alle Elemente eines Vektors, die bestimmte Kriterien erfüllen, zu verarbeiten und zu entfernen und löschen + remove_if für das scheint perfekt. Die Verarbeitung, die ich ausführen werde, hat jedoch Nebenwirkungen, und ich muss sicherstellen, dass die Verarbeitung in der Reihenfolge erfolgt (im Beispiel angenommen, dass ich die Werte in der Reihenfolge drucken möchte, in der sie im ursprünglichen Vektor erscheinen).

Ist es sicher anzunehmen, dass mein Prädikat für jedes Element in Reihenfolge aufgerufen wird?

Ich nehme an, dass die Ausführungsrichtlinien von C++ 17 dies aufklären würden, aber da C++ 17 noch nicht raus ist, hilft das offensichtlich nicht.

Edit: Auch, ist das eine gute Idee? Oder gibt es einen besseren Weg, dies zu erreichen?

+0

Um klar zu sein, würden die Nebenwirkungen den 'Vektor' selbst verändern? Das würde die Iteratoren in jedem Fall ungültig machen, also ist es gut, das zuerst zu überprüfen. Ich würde auch auf irgendwelche Nebenwirkungen achten, die die _values_ in dem 'vector' beeinflussen könnten, da während der Ausführung von' remove_if' die genaue Position irgendeines gegebenen Gegenstandes in dem 'vector' nicht garantiert ist. – ShadowRanger

+0

Nein, die Nebenwirkungen würden den Vektor nicht verändern. Die Nebenwirkungen schreiben tatsächlich einige Dinge in eine Datei. – Solaraeus

+0

Ich denke Wetter oder nicht, es ist strittig. Tun Sie alle Nebenwirkungen, dann machen Sie die Entfernung. –

Antwort

7

Der Standard gibt keine Garantien in der Reihenfolge des Aufrufs des Prädikats.

Was Sie verwenden sollten, ist stable_partition. Sie partitionieren die Sequenz basierend auf Ihrem Prädikat. Dann können Sie die partitionierte Sequenz ausführen, um den von Ihnen gewünschten "Nebeneffekt" auszuführen, da stable_partition die relative Reihenfolge beider Datensätze gewährleistet. Dann können Sie die Elemente aus der vector löschen.

stable_partition muss hier verwendet werden, da erase_if den Inhalt der "gelöschten" Elemente undefiniert lässt.

In Code:

void processVector(std::vector<int> values) 
{ 
    auto it = std::stable_partition(begin(values), end(values), [](int v) {return v % 2 != 0;}); 

    std::for_each(it, end(values), [](int v) {std::cout << v << "\n";}); 

    values.erase(it, end(values)); 
} 
+0

Ja, ich las die Frage erneut, um mich selbst zu überprüfen, löschte dann den Kommentar. Trotzdem: Warum nicht einfach 'erase_if', gefolgt von' for_each'? –

+0

@MooingDuck: Weil 'Erase_if' nicht garantiert, dass * irgendwas in die" leeren "Slots am Ende des Bereichs * verschoben wird. 'stable_partition' tut das. –

-1

Sie sollten verarbeitet werden, um, aber es ist nicht garantiert.

std::remove_if() verschiebt "entfernte" Elemente zum Ende des Containers, sie werden nicht wirklich aus dem Container entfernt, bis erase() aufgerufen wird. Beide Operationen werden möglicherweise bestehende Iteratoren in einer std::vector ungültig machen.

+4

Wo garantiert die Norm die In-Order-Verarbeitung? –

+0

@DafangCao: ja. Mein Fehler.Habe vergessen, dass "Löschen" nichts in der zweiten "Partition" garantiert, was es erlaubt, einen einfacheren Algorithmus zu verwenden. –

+0

@NicolBolas: Ich habe nicht gesagt, dass es * garantiert * war, um in der Reihenfolge verarbeitet zu werden, ich sagte, dass es * in der Reihenfolge verarbeitet werden sollte (siehe "Mögliche Implementierung" auf [cppreference.com] (http: //en.cppreference.com) .com/w/cpp/algorithm/entfernen)). Der Standard sagt dies jedoch für 'remove_if()' in § 25.3.8: "* Complexity: Exactly' last-first'-Anwendungen des entsprechenden Prädikats. * "So kann es kein Element mehr als das Prädikat übergeben einmal (wie eine Art kann). Aber ich denke, das hindert den Algorithmus nicht daran, von Vorne zu Vorne zu arbeiten, statt vorletzte, obwohl Letzteres wahrscheinlicher ist. –