21

In another answer it was stated that prior to C++11, where i is an int, then use of the expression:

*&++i

caused undefined behaviour. Is this true?

On the other answer there was a little discussion in comments but it seems unconvincing.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    In that answer the very knowledgeable "Johannes Schaub - litb" comments that he thinks it's an untrue statement. And gets no response. – Drew Dormann Feb 11 '15 at 21:56
  • 2
    @DrewDormann James Kanze is also very knowledgeable – M.M Feb 11 '15 at 21:57
  • 2
    `*&i` would be perfectly valid, and `++i` returns a reference to `i` so I don't see the problem myself... – Jonathan Potter Feb 11 '15 at 22:04
  • 3
    Wouldn't the undefined behavior concern be in `i = *&++i` or just `*&++i` by itself? –  Feb 11 '15 at 22:07
  • @JonathanPotter: It's not undefined behavior, but it _does_ evaluate to an undefined value. They're both right, they're just talking about subtly different things. – Mooing Duck Feb 11 '15 at 22:15
  • @remyabel my reading of James' post (and Johannes Schaub's reading too) was that when James said "the expression `*&++i` was undefined behavior;" he literally meant what he said ; but perhaps he did intend to write `i = *&++i;` and also later in the same sentence `i = ++i` – M.M Feb 11 '15 at 22:45
  • You might want to be explicit what you mean by *use*, like initializing a reference, using the value (lvalue-to-rvalue-conversion), or what. – Deduplicator Feb 12 '15 at 00:11
  • @Deduplicator the original quote just said *use*. I'm struggling to see how it could be UB in any case that doesn't involve it being part of a larger expression containing `i` – M.M Feb 12 '15 at 00:13
  • Well, iff `++++i` well-defined in C++03, then using the value of (do lvalue-to-rvalue-conversion) on `*&++i` is too. But I cannot see that... – Deduplicator Feb 12 '15 at 00:26
  • @Deduplicator ok let's start with a concrete example like `int x = *&++i;` – M.M Feb 12 '15 at 00:31

2 Answers2

7

It makes little sense to ask whether *&++i in itself has UB. The deferencing doesn't necessarily access the stored value (prior or new) of i, as you can see by using this as an initializer expression for a reference. Only if an rvalue conversion is involved (usage in such context) is there any question to discuss at all. And then, since we can use the value of ++i, we can use the value of *&++i with exactly the same caveats as for ++i.

The original question concerned essentially i = ++i, which is the same as i = *&++i. That was undefined behavior in C++03, due to i being modified twice between sequence points, and is well-defined in C++11, due to the side-effects of the assignment operator being sequenced after the value computations of the left and right hand sides.

It is perhaps relevant to note that the non-normative examples in the C++98 and C++03 standards, were incorrect, describing some cases of formally Undefined Behavior as merely unspecified behavior. Thus, the intent has not been entirely clear, all the way back. A good rule of thumb is to simply not rely on such obscure corner cases of the language, to avoid them: one should not need to be a language lawyer in order to make sense of the code…

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • AFAICS `i = ++i` was well-defined in C++03, as correctly shown by the accepted answer in the linked Q/A. – Columbo Feb 11 '15 at 22:57
  • 1
    @Columbo: If you would be so kind as to summarize or quote, I will endeavour to refute the claim you've seen. I'm unable to find it, sorry. However, since this was very simple in C++03, just absolutely never modify twice or more between sequence points, it may be that you don't need more than that? C++03 §5/4 in [expr]: “Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.” – Cheers and hth. - Alf Feb 11 '15 at 23:04
  • Apparently I misunderstood the notion of sequence points entirely. I thought that the paragraphs quoted by this [answer](http://stackoverflow.com/a/17403467/3647361) would suffice to prove the well-definedness of that expression. But nowhere is anything said about sequence points there (I thought their existence is *implied*, but that seems wrong in hindsight). In fact, it seems that as they occur so rarely they define a lot of conceptually fine code to invoke UB. Fortunately that was fixed in C++11. – Columbo Feb 11 '15 at 23:31
  • @Columbo: Oh. C++03 sequence points were, essentially, the points between statements (but considering function calls it gets more complicated). C++03 §1.9/7 “At certain specified points in the execution sequence called *sequence points*, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.” and §1.9/16 “There is a sequence point at the completion of evaluation of each full-expression”, plus a bit more about function calls in §1.9/17. AFAICS the answer you link to doesn't mention sequence points or C++03. – Cheers and hth. - Alf Feb 11 '15 at 23:40
  • I do understand what sequence points are. I just didn't know that their existence must be explicitly stated, i.e. there is no sequence point between the evaluation of the operands of the assignment operator and the assignment itself because it isn't noted anywhere. – Columbo Feb 12 '15 at 11:41
0

I think the question only makes sense if we deal with the expression:

i = *&++i;

The relevant quote in the C++03 standard would be [expr]/4:

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

i = ++i + 1; // the behavior is unspecified

We can just compare the sequencing of i = *&++i vs i = ++i + 1 to determine that the same rule causes both to be unspecified. They are both statements of the form:

i = f(++i);

For any function f, the reading of i on the left-hand side and the side-effect of the ++i on the right-hand side are not sequenced relative with each other. Hence, undefined behavior.

Barry
  • 286,269
  • 29
  • 621
  • 977