Funktioniert std :: copy_n mit überlappenden Bereichen?

8

Ich habe im C ++ - Standard nach N3485 25.3.1 [alg.copy] gesucht, der 4 Algorithmen definiert:

  • copy
  • copy_backward
  • copy_if
  • copy_n

In der Beschreibung für copy gibt es diesen Hinweis 25.3.1 [alg.copy] / 3:

  

Erfordert: Das Ergebnis darf nicht im Bereich [first, last]

liegen

Das heißt, copy funktioniert nicht immer korrekt, wenn sich die Bereiche überschneiden (ähnlich wie memcpy ).

copy_backward und copy_if haben ähnliche Sprachen, die überlappende Bereiche verbieten (25.3.1 [alg.copy] / 14 bzw. 25.3.1 [alg.copy] / 8).

Allerdings gibt es kein solches Verbot für copy_n , und es gibt kein copy_n_backward . Bedeutet dies, dass copy_n das Richtige tut, wenn sich die Bereiche überschneiden?

(Die Implementierung von copy_n von MSVC ++ scheint an std::memmove zu delegieren, also weiß ich, dass es hier auf MSVC ++ 2013 sicher ist. Aber ich möchte mich nicht darauf verlassen, wenn der Standard das Gegenteil verspricht)

    
Billy ONeal 23.12.2013, 05:03
quelle

2 Antworten

3

Es ist sicher *. Warum? Weil der Standard nicht sagt, dass nicht sicher ist. Sie kopieren Funktionen aus 25.3.1 have Benötigt: für Dinge, die sie benötigen (hier ist das Überschneidungsverbot in den anderen Kopierformen angegeben).

Allerdings sagt copy_n nicht , dass die Bereiche sich nicht überlappen müssen, was bedeutet, dass es in Ordnung ist, da es nicht explizit verboten ist. Wenn es es erfordert, würde es es sagen.

* Edit: Wenn ich "sicher" meinte, meinte ich, dass es kein undefiniertes Verhalten oder ein schlechtes Programm ist. Die Ergebnisse sind jedoch nicht garantiert, was Sie wahrscheinlich beabsichtigten, wenn sich die Speicherbereiche überschneiden. Das Einzige, was wir garantieren können, ist:

  1. Für jede nicht negative Ganzzahl i < n wird *(result + i) = *(first + i) durchgeführt
  2. Der Aufruf der Funktion mit überlappenden Bereichen ist nicht verboten und führt nicht zu undefiniertem Verhalten.

Daraus können wir ableiten, dass, wenn sich die Bereiche überschneiden, die im Ziel gespeicherten Ergebnisse nicht mehr garantiert sind, um eine exakte (in der richtigen Reihenfolge) Kopie der Quelle zu sein. Wir garantieren, dass jeder Wert im Ziel von der Quelle kommt, obwohl genau welche Werte diese sind, hängt von der Überlappung und der genauen Reihenfolge ab, in der die Elemente kopiert werden.

Wenn du also unter "sicher" meinst, dass das Ziel immer eine perfekte Kopie der Quelle hat (wie memmove ), dann ist es nicht "sicher". Aber es ist sicher in dem Sinne, dass es nicht undefiniert / ungültiges Verhalten an und für sich selbst verursacht.

Zur Erinnerung, wir garantieren, dass *(result + i) = *(first + i) für jedes Element im gesamten Bereich ausgeführt wird. Es wird garantiert, dass das Programm bei Überlappung der Bereiche immer noch nicht undefiniert ist. Die Reihenfolge, in der die Elemente kopiert werden, ist nicht gewährleistet. Es ist nicht garantiert, dass, wenn sich die Bereiche überschneiden, die genauen Werte im Ergebnis gespeichert werden (aber wir wissen, dass sie alle aus der Quelle stammen).

    
Cornstalks 23.12.2013, 05:14
quelle
1

Ich stimme Cornstalks 'Antwort zu und stimme ihr +1 zu. Aber Theorie muss durch Übung unterstützt werden.

Ein kurzer Blick auf die Implementierungen von GCC (libstdc ++ - v3) und Clang (libc ++) zeigt, dass ihr copy_n dasselbe ist (oder delegiert an) copy , ohne Unterstützung für Überlappungen beim Verschieben von Objekten nach höher Adressen.

Also gewinnt MSVC diese Runde, zumindest im POD-Fall, der an memmove delegiert.

    
Potatoswatter 23.12.2013 07:13
quelle

Tags und Links