Search code examples
c++c++17undefined-behaviorfunction-callunspecified-behavior

C++ "Undefined" vs "Unspecified" behavior for function calls: f(i=-2, i=-2) is no longer undefined vs f(++i, ++i) is unspecified


I know this is one of those "undefined behavior" questions, but a current cppreference page on the subject (as of C++23) itself gives two example's that I'm having trouble understanding from its rules on sequencing:

f(i = -2, i = -2); // undefined behavior until C++17
f(++i, ++i);       // undefined behavior until C++17, unspecified after C++17

Namely, two questions for the two examples:

    1. Why not "undefined" as of C++17 (for the 1st example)?
    1. Why the "unspecified" instead of "undefined" as of C++17 (for the 2nd example)?

The C++ cppreference page given above gives one rule about the sequencing of function arguments that I can see as relevant here:

  1. In a function call, value computations and side effects of the initialization of every parameter are indeterminately sequenced with respect to value computations and side effects of any other parameter.
  1. So why is f(i = -2, i = -2); not undefined? Did C++17 add language to specify that if the same result would occur regardless of order of evaluation of arguments, it's not undefined?
  2. What's different between these two examples to cause the "unspecified" for f(++i, ++i); as opposed to just simply not undefined?

Solution

  • but the current C++ spec

    This is not C++ spec. This is an amazing and great website called "cppreference". We usually work online with C++ standard draft https://eel.is/c++draft/ . The actual C++ standard has to be purchased https://www.iso.org/standard/79358.html .

    why is f(i = -2, i = -2); not undefined?

    Because it is indeterminately sequenced, as you quoted.

    Did C++17 add language to specify that if the same result would occur regardless of order of evaluation of arguments, it's not undefined?

    No. It added that function arguments are indeterminately sequenced. It was already there that when something is indeterminately sequenced it is not undefined behavior. And indeterminately sequenced may result in different result depending on the actual order of evaluation. The cppreference has:

    Evaluations of A and B are indeterminately sequenced: they may be performed in any order but may not overlap: either A will be complete before B, or B will be complete before A. The order may be the opposite the next time the same expression is evaluated.

    If evaluations are unsequenced, then it is undefined behavior. In cppreference:

    If a side effect on a memory location is unsequenced relative to another side effect on the same memory location, the behavior is undefined.

    What's different between these two examples to cause the "unspecified" for f(++i, ++i);

    So in f(i = -2, i = -2); whichever i = -2 will happen first, f(-2, -2) will be called.

    In f(++i, ++i) it depends when ++ happens vs evaluating i.. Starting with i = 0, you can get f(1, 2), f(2, 1) or f(2, 2) - it is not specified which one.