C++ requires that an OutputIterator type X
support expressions of the form r++
, where r
is an instance of X
. This postfix increment must be semantically equivalent to:
(*) { X tmp = r; ++r; return tmp; }
and must return a type that is convertible to X const&
. In C++11, see 24.2.4 (this is not new, however). In the same section, it says
Algorithms on output iterators should never attempt to pass through the same iterator twice. They should be single pass algorithms.
Given (*), above, say I copy the return value like X a(r++);
Suppose
r
was dereferencable before incrementing, but was not dereferenced. Is it required thata
be dereferencable? If so, mustX a(r++); *a = t;
perform the same assignment as*r++ = t;
would have otherwise? Are there any (other) conditions ona
andr
?Otherwise, suppose
r
was dereferenced/assigned before incrementing, and its incremented value is (also) dereferencable. Which of the following (if any) are well-defined: (a)*a = t;
, (b)++a; *a = t;
, (c)*r = t;
?
Also see the follow-up: Dereference-assignment to a doubly incremented OutputIterator
As you note, r++
has operational semantics
X operator++(int) { X tmp = r; ++r; return tmp; }
I've added the return value as X
because per 24.2.2:2 Iterator
satisfies CopyConstructible
, so it is legitimate to copy construct the return value of r++
into an instance of type X
.
Next, *r++ = o
is required to be valid; this differs from { const X &a(r++); *a = o; }
only in the addition of a sequence point, which merges with the sequence point after return tmp;
in the operational semantics definition above, so the compound statement has the same validity as the expression statement. By invoking CopyConstructible
, { X a(r++); *a = o; }
has the same validity and operational semantics.
In the case
*r = o;
X a(r++);
the following hold:
(a)
*a = o
is invalid because that value of the iterator has already been dereference-assigned;(b)
++a; *a = o
is invalid because that value of the iterator has already been incremented, violating the single-pass requirement, as only (the new value of)r
is required to be incrementable: per the note to 24.2.4:2, Algorithms on output iterators should never attempt to pass through the same iterator twice, although it's not specified what pass through means in this context;(c)
*r = o
is valid, because the only difference to*r = o; r++; *r = o
overall is the continued existence of a copy of the original value ofr
, which perCopyConstructible
requirements has no semantic effect on the value copied from.
Another interesting question is (for a non-dereference-assigned r
):
X a(r);
++r;
++r;
*a = o;
This isn't covered by the standard directly, but from CopyConstructible
it appears it should be valid.
来源:https://stackoverflow.com/questions/11876128/c-outputiterator-post-increment-requirements