What are these estimates in the calling function that were not specially ordered in front of the body of the called function?

[intro.execution] / 15 contains these statements on page 11 of N4140 (emphasis mine):

When a function is called (regardless of whether the function is built-in), each calculation of the value and side effect associated with any argument of the expression or postfix expression denoting the called function are sequenced before each expression or statement in the body of the called function is executed. [Note: the value of the calculation and the side effects associated with the various arguments of the expression are not affected. -end note] Every estimate in the calling function (including other function calls) that is not otherwise sequenced before or after the execution of the body of the called function is vaguely ordered with respect to the execution of the called function . nine

9) In other words, the execution of functions does not alternate with each other.

I am wondering what are these estimates in the calling function that are not specifically ordered prior to the execution of the body of the called function?


* Edit * I answer both answers in the question "sequence before" and "Each evaluation in the calling function" in C ++ has nothing to do with my question. Please read my question and the answers given therein. See also my comment on the question below from @CoryKramer.


* Edit 2 * This is probably the answer to my question. See Proposal No. 3 in DR 1949 :

Each estimate in the calling function (including other function calls) that is not otherwise sequenced before or after the body of the called function is indefinitely sequenced with respect to the execution of the called function For each call to the function F for each estimate A that occurs inside F and each estimate B, which is not found in F, but is estimated in the same stream as part of the same signal processor (if available) or sequenced a before B or B sequenced to 9 A. [Note: esl A and B would otherwise not sequenced, they will be ordered indefinitely. -end note]

+6
source share
2 answers

If you have two functions returning int

 int Foo(); int Bar(); 

Then you have a call function

 void SomeFunction(int x, int y); 

Then the calling code looks like

 SomeFunction(Foo(), Bar()); 

They say that the execution order of Foo and Bar is indefinite.

+4
source

The answer from CoryKramer is absolutely correct, but perhaps not well developed. The clarification in DR 1949 does not matter.

The key is clause 13 of section 1.9, which defines the โ€œsequenced toโ€ relationship as a partial order and provides four possibilities for two ratings A and B:

  • A sequenced to B

  • B sequenced to A

  • One of (1) or (2) is satisfied, but the standard does not indicate which. In this case, we say that A and B are indefinitely sequenced.

  • Neither (1) nor (2) is satisfied. In this case, we say that A and B are not affected.

There is a difference between undefined sequencing and illogical, and it is this difference that is considered in paragraph 15. Paragraph 15 begins with a general rule (emphasized by me):

Except where noted, estimates of the operands of individual operators and subexpressions of individual expressions are not affected.

The consequence of this is that in a function call

 f(argument1, argument2); 

estimates of argument1 and argument2 have no consequences. This makes the following undefined behavior:

 f(i++, i++); 

But suppose we had:

 int incr(int& i) { return i++; } 

and instead we wrote:

 f(incr(i), incr(i)); 

If we applied the general rule, it would also be undefined behavior with exactly the same argument: both estimates are not subject to a sequence, therefore the estimates of the bodies of two function calls are not subject, and we end up with two disjoint changes to the same variable.

But this is really undesirable, as it will lead to chaos. [It should be noted that the above example is severely simplified; the two functions can be completely different, and the general variable cannot be named. In particular, as a general case, both functions can send output to std::cout , thus performing a mutable operation on the same common object ( std::cout ).]

Thus, an explicit exception is made for function calls: the function evaluation body is always ordered with respect to the subexpressions of the expression that contains the function call. So in

 f(incr1(i), incr2(i)); 

because these are function calls, the evaluation of the bodies incr1 and incr2 indefinitely sequenced, and has no consequences, and since both orders lead to the fact that i doubles, the value of i at the end of the evaluation of the argument list is clearly defined. Also, the actual arguments passed to f are not defined, not undefined; either the first or second will be larger, but they will not be equal.

This exception does not apply to the evaluation of the calls themselves, but only to the evaluation of the bodies of the called function. So f(g(i++), h(i++)) still exists undefined, because evaluating two i++ subexpressions is not part of evaluating the body of any of the functions.

Two side problems

  • Section 15 also extends this exception to function calls resulting from language semantics, including operator overrides, with an interesting result that

     f(i++, i++); 

    is undefined, not undefined if i is an instance of an object with operator++(int) overriding. Similarly

     f(std::cout << 'a', std::cout << 'b'); 

    will cause ab or ba to be sent to std::cout (unspecified), but not undefined.

  • The point of DR 1949 is that "sequenced after" was never formally defined. Therefore, instead of saying that โ€œA is sequenced before or after Bโ€, the more precise wording โ€œeither A is sequenced before B or B is sequenced to Aโ€. You can achieve the same logical effect by formally defining that "A is sequenced after B" because "B is sequenced to A". DR 1949 does both.

+2
source

All Articles