Stateful Funktoren & STL: Undefiniertes Verhalten

8

Ich folge diesem Funktionsobjekte-Lernprogramm

Kopieren-Pasta unten:

Ich kann folgendes nicht verstehen:

Prädikate sollten immer als zustandslose Funktionsobjekte implementiert werden, um unerwartete Ergebnisse zu vermeiden. Es gibt keine Garantie, wie oft ein Algorithmus das Prädikat intern kopieren könnte. Wenn also Prädikate als statusbehaftete Funktionsobjekte implementiert werden, kann dies zu unerwarteten Ergebnissen führen.

Das Beispiel ist wie folgt:

%Vor%

Wenn ich es richtig verstehe (lese), versucht es das im Vektor als 2 markierte Element zu entfernen. Der remove_if-Algorithmus gibt ein neues Ende des Containers zurück und versucht, alles zu löschen.

Ausgabe:

%Vor%

Natürlich wurde nicht nur das zweite Element entfernt, sondern auch das vierte. Die Antwort auf diese Kuriosität ist einfach, dass der verwendete Algorithmus 'remove_if' intern das Prädikat während seiner Ausführung kopiert. Und diese interne Kopie erstellt ein neues Prädikatobjekt, das seinen ursprünglichen Zustand enthält.

Obwohl ich lesen kann, was zu geschehen scheint, kann ich mir nicht vorstellen, was hinter den Kulissen passiert, die sogar das vierte Element markiert haben, das an das Ende des Containers verschoben werden soll. Hat dies mit einem Algorithmus zu tun, der Single-Pass oder Multiple-Pass ist? (Ich wäre auch dankbar, wenn mir jemand in die richtige Richtung zeigen könnte, wie ich das gleiche ableiten kann)

Nebenbei bemerkt, wenn ich das Löschen & amp; Notiere die Ausgabe.

%Vor%

Was verursacht, dass der Container beschädigt wird?

    
Ricko M 24.05.2011, 15:37
quelle

1 Antwort

20

Die Bedeutung dieses Zitats sollte zum Nennwert genommen werden. Für die Mehrheit der STL-Algorithmen sollten Sie Ihren Prädikat-Funktor nicht so implementieren, dass er beobachtbare Zustände (AKA "Nebenwirkungen") aufweist, denn:

  • die Iterationsreihenfolge über den Container ist nicht definiert,
  • Der Algorithmus kann Kopien des Funktors erstellen,
  • Der Algorithmus kann von bei Zustandslosigkeit abhängen, um den Inhalt des Containers nicht zu beschädigen oder abzustürzen.

Der einfachste Weg dies zu erzwingen, ist operator() als const zu definieren.

Es gibt Ausnahmen, z. B. for_each , für die keine der oben genannten Optionen zutrifft. Sie können hier stateful funktors verwenden. Weitere Informationen finden Sie in diesem ausgezeichneten Artikel: Ссылка .

Hinter den Kulissen können die Autoren Ihrer STL-Implementierung die remove_if (und andere Algorithmen) beliebig schreiben, solange sie den Anforderungen des Standards entsprechen. Es gibt keinen wirklichen Grund, sich zu sehr Gedanken darüber zu machen, warum Sie das Verhalten, das Sie sehen, erhalten, außer zu erkennen, dass es nicht definiert ist. Wenn Sie die Einzelheiten wissen möchten, würde ich nur den Code für remove_if in der STL-Implementierung, die Sie verwenden, betrachten.

Wie für Ihre Randnotiz; Das ist nicht "Korruption", es ist einfach ein Artefakt davon, wie remove_if funktioniert (dies würde sogar für ein gültiges Prädikat auftreten). Die einzige Voraussetzung ist, dass alle Elemente zu links von pos gültig sind (weil sie beibehalten werden sollen). Es gibt keine Anforderungen dafür, welche Elemente ab pos existieren (siehe hier ). (Kapitel 32 von " Effective STL " von Scott Meyers hat eine gute Erklärung dafür, warum remove_if (und so weiter) sich so verhält).

    
Oliver Charlesworth 24.05.2011, 15:40
quelle

Tags und Links