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
rwas dereferencable before incrementing, but was not dereferenced. Is it required thatabe dereferencable? If so, mustX a(r++); *a = t;perform the same assignment as*r++ = t;would have otherwise? Are there any (other) conditions onaandr?Otherwise, suppose
rwas 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 = ois invalid because that value of the iterator has already been dereference-assigned;(b)
++a; *a = ois invalid because that value of the iterator has already been incremented, violating the single-pass requirement, as only (the new value of)ris 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 = ois valid, because the only difference to*r = o; r++; *r = ooverall is the continued existence of a copy of the original value ofr, which perCopyConstructiblerequirements 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