Reading the result of the POD precursor does not result in undefined behavior. Why exactly?

This is a stupid question. :)

[EDIT: silly or not, this turned out to be a C ++ complexity issue, see UPDATE_2]

Let's pretend that:

int a = 0; // line 1 int b = ++a; // line 2 

What happens on line 2 (note that numbers are only markers and do not indicate the exact order):

  = [1: write result of (3) to result of (2)] /\ [2: take "b" l-value] [3: convert result of (4) to an r-value ] | [4: take "a" l-value, "increment" and return it] 

The “record” in (4) is “ordered” before “reading” in (3), and since there are no sequence points between the points, the side effect is not guaranteed earlier (3) (there is also a “read” inside (4), but it is ordered up to “ records, "so it doesn’t give UB).

So where is the error in the above?

[UPDATE aimed at non-experienced lawyers with consistent points :)]

In other words, the problem is this:

  • It seems that there is a “competition”, first of all, whether the conversion is l-value-to-r ("read") or increment ("write").

  • In C, this will give UB, according to JTC1 / SC22 / WG14 N926 "Point Sequence Analysis" * (see, for example, example 5: int x,y; (x=y) + x; // UB ).

  • Please note that this will not be the case if postincrement will be used, since (3) and (4) will be the same [(3): take "a" value l, convert it to r-value and return that r-value] with a side effect, "write" is delayed until the next point in the sequence appears

_

(*) This looks like the cleanest systematic rationale for a topic posed by members of the C99 Standards Committee.

[UPDATE_2]

  • Lesson learned: never judge C ++ by the rules of C :)). I did exactly what wondered why the N926 (which purely describes the way things are C99) was "not clear enough" on the subject of preincrements giving l-values.

  • The question arises: how to build a similar justification for C ++, since it does not exist, because even in the case of C, simply interpreting the standard is rather complicated, and the C ++ language is much more complicated and unclear.

[UPDATE_3]

A discussion of some relevant topics (at least in the ~ new half) in "Uncertainty of the general expression." , plus the issue is discussed by committee members here (see "222. Sequence Points and Lvalue Returning Operators").

+7
c ++ c standards language-lawyer
source share
2 answers

I think the solution may be in the wording "++ i". It says: "Value is the new value of the operand, it is the value of lvalue." And the behavior is undefined in 5/4 with "In addition, the previous value should be accessed only to determine the value to be saved."

So, we do not get access to the previous, but new value. And then everything will be all right. This seems to be a very thin line between undefined behavior and specific behavior.

In fact, the "previous value" sounds to me like "the value that the object had at the previous point in the sequence." And if interpreted this way, this construction looks undefined. But if we directly compare the wording "++ i" in 5.3 / 2 - 5/4, we are confronted with a "new value" and a "previous value", and things are "bent" to a specific behavior ("++ I" looks into the value "I" at the next point in the sequence and will produce this value as the contents of the resulting lvalue "++ I").

+2
source share

Basic sentence in C ++ 5/4

Between the previous and next points of the sequence, a scalar object must have a value that its stored value is changed no more than once by evaluating the expression.

(And the sentence quoted by Johannes is the next, subordinate.)

Which scalar object do you suspect has more than once modified stored parameter? a and b change once on line 2, so there is no problem.

(A similar language is in 6.5 / 2 of the C standard.)


EDIT:

The "record" in (4) is "ordered" before the "reading" in (3), and since there are no sequence points between the points, the side effect is not guaranteed earlier (3)

When reading your question again, I think the confusion arises from the confusing way of thinking about ++a : the expression does not really look into the future meaning of a . Rather, it can help to think of ++a as "return a+1 and as an increment of side effect a , at your leisure (before the next point in the sequence)."

So who cares if this is a side effect before or after (3)? The value of the expression that is passed in (3) is already defined.

+1
source share

All Articles