Is this code clearly defined?

I suspect that the following chain of functions will lead to an unspecified sequence in accordance with C ++ standards (suppose C ++ 0x). I just want confirmation, and if anyone can give an explanation, I would appreciate it.

#include <iostream> struct TFoo { TFoo(int) { std::cout<<"TFoo"<<std::endl; }; TFoo foobar1(int) { std::cout<<"foobar1"<<std::endl; return *this; }; TFoo foobar2(int) { std::cout<<"foobar2"<<std::endl; return *this; }; static int bar1() { std::cout<<"bar1"<<std::endl; return 0; }; static int bar2() { std::cout<<"bar2"<<std::endl; return 0; }; static int bar3() { std::cout<<"bar3"<<std::endl; return 0; } }; int main(int argc, char *argv[]) { // is the sequence well defined for bar1, bar2 and bar3? TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3()); } 

* edit: removed the __fastcall specifier for functions (not required / related to the question).

+8
c ++ order-of-evaluation sequence-points c ++ 11
source share
2 answers

The evaluation procedure is not specified. The corresponding section of the C ++ 0x spec project is 1.9, paragraphs 14 and 15:

14 Each calculation of a value and the side effect associated with the full expression are sequenced before each value is calculated and the side effect associated with the next full expression to be evaluated.

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

Here's the corresponding full expression:

 TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3()); 

Thus, evaluating his subexpressions does not matter (unless an exception that I missed is indicated).

I am sure that earlier standards include a language that has the same effect, but in terms of "sequence points."

[edit]

Paragraph 15 also states:

When a function is called (regardless of whether the function is built-in), each value calculation and side effect associated with any argument expression, or with the postfix expression indicating the function to be called, are sequenced before each expression or statement is executed in the body of the function being called. [Note: value calculations and side effects associated with different expressions of the argument have no consequences. - end note]

A "postfix expression indicating the function to be called" is similar to foo().bar in foo().bar() .

The “note” here simply states that the order in which the argument is evaluated is not an exception to the default “unspecified order”. In conclusion, not a single evaluation order associated with the "postfix expression denoting the called function"; or, if you want, the order in which the expression evaluates to the this argument. (If there were an exception, this would be a natural place to point it out. Or, perhaps, section 5.2.2, which talks about function calls. None of the sections says anything about the evaluation order for this example, so it is not listed. )

+8
source share

Yes, the order in which function arguments are evaluated is not specified.

For me, gcc 4.5.2 on linux produces

 bar3 bar2 bar1 TFoo foobar1 foobar2 

but clang ++ on linux and gcc 3.4.6 on Solaris produce

 bar1 TFoo bar2 foobar1 bar3 foobar2 

To analyze a simpler example, TFoo(0).foobar1(TFoo::bar2()); is a call to TFoo::foobar1 , which takes two arguments: the result of the TFoo(0) subexpression (as the hidden this argument) and the result of the Tfoo::bar2() subexpression. For me, gcc executes bar2() first, then the TFoo constructor, and then calls foobar1() , while clang ++, for example, first executes the TFoo constructor, then bar2() , and then calls foobar1() .

+1
source share

All Articles