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 that a
be dereferencable? If so, must X a(r++); *a = t;
perform the same assignment as *r++ = t;
would have otherwise? Are there any (other) conditions on a
and r
?
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
In Pre-Increment, the operator sign (++) comes before the variable. It increments the value of a variable before assigning it to another variable. In Post-Increment, the operator sign (++) comes after the variable. It assigns the value of a variable to another variable and then increments its value.
2) Post-increment operator: A post-increment operator is used to increment the value of the variable after executing the expression completely in which post-increment is used. In the Post-Increment, value is first used in an expression and then incremented.
Pre increment directly returns the incremented value, but post increments need to copy the value in a temporary variable, increment the original and then returns the previous made copy.
Decrement operator decrease the value by one. Pre-increment (++i) − Before assigning the value to the variable, the value is incremented by one. Post-increment (i++) − After assigning the value to the variable, the value is incremented. The following is the syntax of pre and post increment.
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 of r
, which per CopyConstructible
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With