Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ OutputIterator post-increment requirements

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++);

  1. 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 ?

  2. 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

like image 455
nknight Avatar asked Aug 09 '12 02:08

nknight


People also ask

How pre increment and post increment works in C?

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.

How does post increment work?

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.

How does pre increment and Post increment work in for loop?

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.

What is difference between pre and post increment decrement?

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.


1 Answers

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.

like image 175
ecatmur Avatar answered Oct 08 '22 14:10

ecatmur