C ++ erfordert, dass ein OutputIterator-Typ X
unterstützt Ausdrücke der Form r++
, wobei r
eine Instanz von X
ist. Dieses Postfixinkrement muss semantisch äquivalent sein zu:
(*) { X tmp = r; ++r; return tmp; }
und muss einen Typ zurückgeben, der in X const&
konvertierbar ist. In C ++ 11, siehe 24.2.4 (dies ist jedoch nicht neu). Im selben Abschnitt heißt es
Algorithmen in Ausgabe-Iteratoren sollten niemals versuchen, denselben Iterator zweimal zu durchlaufen. Sie sollten single pass Algorithmen sein.
Gegeben (*), oben, sagen wir, ich kopiere den Rückgabewert wie X a(r++);
Angenommen, r
wurde vor dem Inkrementieren dereferenziert, wurde aber nicht dereferenziert. Ist es erforderlich, dass a
dereferenzierbar ist? Wenn ja, muss X a(r++); *a = t;
die gleiche Zuweisung ausführen wie *r++ = t;
andernfalls? Gibt es (andere) Bedingungen für a
und r
?
Angenommen, r
wurde vor dem Inkrementieren dereferenziert / zugewiesen, und sein inkrementierter Wert ist (auch) dereferenzierbar. Welche der folgenden (wenn überhaupt) sind klar definiert:
*a = t;
, (b) ++a; *a = t;
, (c) *r = t;
?
Siehe auch das Follow-up: Dereferenzierungs-Zuordnung zu einem doppelt inkrementierten OutputIterator
Wie Sie feststellen, hat r++
eine funktionierende Semantik
Ich habe den Rückgabewert als X
hinzugefügt, weil per 24.2.2: 2 Iterator
erfüllt CopyConstructible
. Daher ist es legitim, den Rückgabewert von r++
in eine Instanz vom Typ% co_de zu kopieren %.
Als nächstes muss X
gültig sein; Dies unterscheidet sich von *r++ = o
nur durch die Addition eines Sequenzpunkts, der mit dem Sequenzpunkt nach { const X &a(r++); *a = o; }
in der obigen operationalen Semantik Definition zusammenfällt, sodass die zusammengesetzte Anweisung die gleiche Gültigkeit wie der Ausdruck hat Erklärung. Durch den Aufruf von return tmp;
hat CopyConstructible
die gleiche Gültigkeit und operative Semantik.
Im Fall
%Vor%das folgende Halten:
(a) { X a(r++); *a = o; }
ist ungültig, weil dieser Wert des Iterators bereits dereferenziert wurde;
(b) *a = o
ist ungültig, da dieser Wert des Iterators bereits inkrementiert wurde, was die Anforderung für einen einzigen Durchlauf verletzt, da nur (der neue Wert von) ++a; *a = o
inkrementierbar sein muss: per die Anmerkung zu 24.2.4: 2, Algorithmen auf Ausgabe-Iteratoren sollten niemals
Versuche, denselben Iterator zweimal zu durchlaufen , obwohl in diesem Kontext nicht angegeben ist, was durch bedeutet;
(c) r
ist gültig, weil der einzige Unterschied zu *r = o
insgesamt das Fortbestehen einer Kopie des ursprünglichen Wertes von *r = o; r++; *r = o
ist, die pro r
keine semantische Wirkung hat auf den Wert kopiert von.
Eine weitere interessante Frage ist (für eine nichtdereferenzierte CopyConstructible
):
Dies wird nicht direkt vom Standard abgedeckt, aber von r
scheint es gültig zu sein.
Tags und Links c++ iterator post-increment