C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Parameter evaluation order?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Groman
Guest





PostPosted: Tue Aug 26, 2003 12:41 am    Post subject: Parameter evaluation order? Reply with quote



Hello,

I recently bumped into a relatively interesting problem with a C++
project of mine. After years and years of heavy C++ programming, I'm
surprised that this has never occured to me and I have not discovered
it before. Imagine my surprise when I discovered that function
parameters are not evaluated left-to-right. Now, it makes sense to me
why that is on my platform, but this is not portable behaviour is it?
i.e. I guess what I am asking is whenever the parameter evaluation
order is defined in any C++ standard or is it considered ambiguous.

For example, say we have a function foo as follows

void foo(int a, int b)
{
std::cout << a << " " << b << " ";
}

and we call it as follows:

int x = 5;
foo(--x, ++x);

Now for all intents and purposes the results will be ambigious. For
all we know, this will run on a parallel machine and both parameter
evaluations will execute in parallel giving foo(4, 6). On a stack
machine, such as an ia32, it might evaluate right to left(and it does
on at least 2 C++ implementations I tried - Borland and Gnu) and it
will be foo(5, 6). And I theorize that on a linear but RISC
register-passing implementation it might become foo(4, 5). After the
function call, x will undoubtebly be 5, however.

Now, we can just call such code "ambigious" and decide to avoid
parameter evaluations that affect other parameter evaluations in the
same code, but I'd really like to hear some semi-official/expert
stance on the subject.

Thank you very much,

Sincerely,

Yuriy Romanenko

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Jack Klein
Guest





PostPosted: Tue Aug 26, 2003 8:38 am    Post subject: Re: Parameter evaluation order? Reply with quote



On 25 Aug 2003 20:41:17 -0400, [email]usenet (AT) carrietech (DOT) com[/email] (Groman) wrote in
comp.lang.c++.moderated:

Quote:
Hello,

I recently bumped into a relatively interesting problem with a C++
project of mine. After years and years of heavy C++ programming, I'm
surprised that this has never occured to me and I have not discovered
it before. Imagine my surprise when I discovered that function
parameters are not evaluated left-to-right. Now, it makes sense to me
why that is on my platform, but this is not portable behaviour is it?
i.e. I guess what I am asking is whenever the parameter evaluation
order is defined in any C++ standard or is it considered ambiguous.

Have you ever read a book on C++? There is a perfectly good term for
this, in both C and C++, first defined in the original ANSI standard
for C in 1989 and incorporated in every version of the C and C++
language standards since then.

The order of evaluation of function arguments is "unspecified
behavior". This term has a very precise definition, here is the one
for the ANSI/ISO C++ standard:

"1.3.13 unspecified behavior
behavior, for a well-formed program construct and correct data, that
depends on the implementation. The implementation is not required to
document which behavior occurs. [Note: usually, the range of possible
behaviors is delineated by this International Standard. ]"

The compiler can evaluate arguments to a function in any order. In
fact, if you call the same function multiple times, it can evaluate
them in a different order each time. And it is not required to tell
you what order or why, although many compilers do.

The range of evaluation is only limited by the existence of sequence
points. The generated code cannot begin evaluating arguments to a
function until it has completed executing the statement preceding the
function call. And it must finish evaluating all arguments to the
function before the actual function call.

Quote:
For example, say we have a function foo as follows

void foo(int a, int b)
{
std::cout << a << " " << b << " ";
}

and we call it as follows:

int x = 5;
foo(--x, ++x);

If you call it like that, you have undefined behavior. There is no
sequence point between the two modifications of x. The comma
separator between function call arguments is not the comma operator,
which does impose a strict ordering and a sequence point.

Quote:
Now for all intents and purposes the results will be ambigious. For

No, the result will specifically be undefined. Invoking undefined
behavior in a C++ (or C) program is like dividing by 0 in mathematics.
There is absolutely no correct answer. Once your program executes
that function call, it stops being bound by the rules of the C++
standard. To be specific, here is how the C++ standard describes
undefined behavior:

"1.3.12 undefined behavior
behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements. Undefined behavior may also be expected when
this International Standard omits the description of any explicit
definition of behavior. [Note: permissible undefined behavior ranges
from ignoring the situation completely with unpredictable results, to
behaving during translation or program execution in a documented
manner characteristic of the environment (with or without the issuance
of a diagnostic message), to terminating a translation or execution
(with the issuance of a diagnostic message). Many erroneous program
constructs do not engender undefined behavior; they are required to be
diagnosed. ]"

Quote:
all we know, this will run on a parallel machine and both parameter
evaluations will execute in parallel giving foo(4, 6). On a stack
machine, such as an ia32, it might evaluate right to left(and it does
on at least 2 C++ implementations I tried - Borland and Gnu) and it
will be foo(5, 6). And I theorize that on a linear but RISC
register-passing implementation it might become foo(4, 5). After the
function call, x will undoubtebly be 5, however.

As far as C++ is concerned, there is neither requirement not guarantee
that x will be 5. It could be anything, that's what the phrase
"imposes no requirements" means.

Quote:
Now, we can just call such code "ambigious" and decide to avoid

No, we can't call such code "ambiguous". The language standard gives
us three distinct terms to define what can happen when we venture
outside the range of a strictly conforming program:

First, there is implementation-defined behavior, which may vary from
compiler to compiler. The implementation must select one of the
possible alternatives allowed by the standard, and document its
choice.

Second there is unspecified behavior, which I quoted above. Again an
implementation must select one of the possible alternatives allowed by
the standard, but it need not document its choice. Nor need it be
consistent in its choice.

Finally there is undefined behavior, such as dereferencing a null
pointer, dividing by 0, or modifying an object more than once without
an intervening sequence point. In that case, the implementation can
do anything, including refusing to compiler your program in the first
place or crashing when you run it.

Quote:
parameter evaluations that affect other parameter evaluations in the
same code, but I'd really like to hear some semi-official/expert
stance on the subject.

Thank you very much,

Sincerely,

Yuriy Romanenko

Let's change your sample code a little:

int x = 5;

int inc_x() { return ++x; }
int dec_x() { return --x; }

void foo(int a, int b)
{
std::cout << a << " " << b << " " << endl;
}

/* in some function */
foo(dec_x(), inc_x());

Now we have removed the undefined behavior. The compiler must call
either dec_x() or inc_x() first, and there is a sequence point in each
function, so x is not modified twice without a sequence point in
between.

What is left if the unspecified behavior of the order of function
argument evaluation. The compiler may output "4 5", or it may output
"6 5". These are the only two possibilities, and the value of x at
the end will be 5. But it does not have to tell you which order, and
in fact if you call the function three times in a row, it could
output:

4 5
6 5
4 5

I don't know of any implementation that does so, and there probably
aren't any, but such an implementation would be conforming to the C++
standard.

If you want guarantees, do not include implementation-defined,
unspecified, or undefined behavior in your programs. Then they should
be portable to any conforming C++ compiler.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Tue Aug 26, 2003 8:43 am    Post subject: Re: Parameter evaluation order? Reply with quote



Groman wrote:
Quote:
int x = 5;
foo(--x, ++x);

Now for all intents and purposes the results will be ambigious. For
all we know, this will run on a parallel machine and both parameter
evaluations will execute in parallel giving foo(4, 6). On a stack
machine, such as an ia32, it might evaluate right to left(and it does
on at least 2 C++ implementations I tried - Borland and Gnu) and it
will be foo(5, 6). And I theorize that on a linear but RISC
register-passing implementation it might become foo(4, 5). After the
function call, x will undoubtebly be 5, however.

I think the FAQ mentions this problem. Anyhow, you can't even count on the
x being 5 afterwards. You are (I hope I get it right) modifying the
variable twice between sequence-points and that yields
implementation-defined behaviour.

{Much worse, it is undefined behaviour. -mod}

cheers

Uli

--
Questions ?
see C++-FAQ Lite: http://parashift.com/c++-faq-lite/ first !


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Andrea Griffini
Guest





PostPosted: Tue Aug 26, 2003 1:17 pm    Post subject: Re: Parameter evaluation order? Reply with quote

On 25 Aug 2003 20:41:17 -0400, [email]usenet (AT) carrietech (DOT) com[/email] (Groman) wrote:

Quote:
Now, we can just call such code "ambigious" and decide to avoid
parameter evaluations that affect other parameter evaluations in the
same code, but I'd really like to hear some semi-official/expert
stance on the subject.

I'm no officer and not even a real expert, but IMO it's way
worse that just ambiguous... If my old docs are still valid
and if I interpreted them correctly there is no sequence point
between evaluation of the parameters of a function (see
[intro.execution]) and modifying x twice without an intervening
sequence point is undefined behaviour (see [expr]).

So, in theory and as far as the C++ standard can say, you can
also get calls to foo(11,47) or even a demon flying off from
your nose.

Things are different if the different "evaluations" performed
in the argument list imply function calls (note that every
overloaded operator is also a function call), because in that
case you may have "just" an unspecified order of evaluation
(execution) of those calls.

In other words...

int x;

void foo(int a,int b)
{
...
}

int dec(int& x) { --x; return x; }
int inc(int& x) { ++x; return x; }

int main()
{
x = 5;
foo(inc(x),dec(x));
}

Is legal (and nasty) C++ code where you can't guess portably
what are the values that will be passed to foo: they can be
(6,5) or (5,4) but they can't be (5,5) or (6,4) as at the
point foo is called inc was called before dec or after dec ...
moreover if foo inspects the global variable x the value
found will be surely 5.

Note also that if you change the return value of inc/dec to
int& then the (5,5) case is possible too as it's unspecified
when the conversion int&->int will be done, so the compiler
*may* also call inc, then call dec, then then do both the
reference->value conversions and then call foo.

What does all this mean ? Just avoid dependence on order
of evaluation of subexpressions Smile ...

The most common error in this area is in my experience
assuming that

std::cout << f() << g() << h();

will call f, then g and last h while this is not guaranteed
at all as those calls can be executed in any order.

HTH
Andrea

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Francis Glassborow
Guest





PostPosted: Tue Aug 26, 2003 2:42 pm    Post subject: Re: Parameter evaluation order? Reply with quote

In article <ae953bad.0308251024.52d68534 (AT) posting (DOT) google.com>, Groman
<usenet (AT) carrietech (DOT) com> writes
Quote:
void foo(int a, int b)
{
std::cout << a << " " << b << " ";
}

and we call it as follows:

int x = 5;
foo(--x, ++x);

Now for all intents and purposes the results will be ambigious. For
all we know, this will run on a parallel machine and both parameter
evaluations will execute in parallel giving foo(4, 6). On a stack
machine, such as an ia32, it might evaluate right to left(and it does
on at least 2 C++ implementations I tried - Borland and Gnu) and it
will be foo(5, 6). And I theorize that on a linear but RISC
register-passing implementation it might become foo(4, 5). After the
function call, x will undoubtebly be 5, however.

No it will not:-)

In C++ as in C, the order of evaluation of subexpressions is
unspecified, the only requirement is that a sub-expression is fully
evaluated before it is first used. This is C++ programming 101 level
knowledge.

But worse, any code that attempts to write more than once to the same
variable without an intervening sequence point has undefined behaviour
so:

foo(--x, ++x);

would have undefined behaviour even if the order of evaluation were
specified unless x is a udt where increment and decrement had been
provided as user defined overloads of the operators.

If you have had years and years of programing without knowing such
fundamentals of C++ you have a big learning problem ahead of you because
you will have to retune your instincts so that seeing such code
immediately fires off red warning lights. You also might like to
consider what other assumptions you may be making about C++ that are not
actually valid.

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Tue Aug 26, 2003 6:39 pm    Post subject: Re: Parameter evaluation order? Reply with quote

[email]usenet (AT) carrietech (DOT) com[/email] (Groman) wrote in message
news:<ae953bad.0308251024.52d68534 (AT) posting (DOT) google.com>...

Quote:
I recently bumped into a relatively interesting problem with a C++
project of mine. After years and years of heavy C++ programming, I'm
surprised that this has never occured to me and I have not discovered
it before. Imagine my surprise when I discovered that function
parameters are not evaluated left-to-right. Now, it makes sense to me
why that is on my platform, but this is not portable behaviour is it?
i.e. I guess what I am asking is whenever the parameter evaluation
order is defined in any C++ standard or is it considered ambiguous.

C++ simply follows the C rules here -- the order of evaluation is
unspecified, and the compiler is free to reorder in any way it wishes.
I've used compilers which evaluate from left to right, from right to
left, and even some that mix, evaluating parts of one parameter, then
another parameter, then returning to finish evaluation of the first
parameter.

The only restriction is that the compiler cannot evaluate function calls
in parallel -- once a function is entered, that function will be
finished before anything outside of the function takes place.

And I'm rather surprised that you weren't aware of this. It is a fairly
basic issue, which should be explained in any C or C++ book.

Quote:
For example, say we have a function foo as follows

void foo(int a, int b)
{
std::cout << a << " " << b << " ";
}

and we call it as follows:

int x = 5;
foo(--x, ++x);

This is even worse. According to the standard, this is undefined
behavior. The standard places no restrictions on what happens.

This is a FAQ, and is well explained in the C FAQ (which also pretty
much holds for C++). See in particular the section on expressions
([url]http://www.eskimo.com/~scs/C-faq/s3.html)[/url].

Quote:
Now for all intents and purposes the results will be ambigious. For
all we know, this will run on a parallel machine and both parameter
evaluations will execute in parallel giving foo(4, 6).

For all we know, this will run on a parallel machine which will deadlock
if both processors attempt to write the same memory cell at the same
time. Since no legal C or C++ program may attempt such a thing, the
compiler is not required to generate code to avoid it.

Quote:
On a stack machine, such as an ia32, it might evaluate right to
left(and it does on at least 2 C++ implementations I tried - Borland
and Gnu) and it will be foo(5, 6). And I theorize that on a linear but
RISC register-passing implementation it might become foo(4, 5). After
the function call, x will undoubtebly be 5, however.

Not according to the standard, and in fact, not necessarily in practice,
supposing a parallel architecture. And most architectures today are
parallel at the lowest levels. Older architectures, such as IA32, have
built-in hardware synchronization, for reasons of backward
compatibility, but most newer RISC processors leave this up to the
(compiler generated) program.

Quote:
Now, we can just call such code "ambigious" and decide to avoid
parameter evaluations that affect other parameter evaluations in the
same code, but I'd really like to hear some semi-official/expert
stance on the subject.

The official statement is simple:

1. The order of evaluation in an expression, in the absense of sequence
points (see below), is unspecified, and the compiler can pretty much
do what it wants.

2. If an object is modified in an expression, any other attempt to
modify the object, or any attempt to access it for any reason other
than to determine the new value, without an intervening sequence
point, is undefined behavior. See question 3.3 in the C FAQ, cited
above.

If any possible reordering allowed in 1, above, results in a
violation of this rule, then it is undefined behavior.

3. In addition, the compiler can reorder or modify legal code in just
about any way it pleases, as long as the observable behavior which
results corresponds to some legal reordering (according to 1).
(Since violations of rule 2 result in undefined behavior, not even
the guarantee of respecting observable behavior holds then.)

The key to these rules is something the standard calls sequence points,
which defines a PARTIAL ordering, which the compiler must more or less
respect. (The observable results must be as if the partial ordering was
respected.) The end of a full expression is a sequence point, as is a
function call, and the '?', ',', '||' and '&&' operators. (Attention
here: the ',' operator is a sequence point, put a ',' used as a
separator ISN'T.) In particular, any side effects of evaluating a
parameter must take place before the function is called; if i is a
global variable, in "f( i ++ )", the value visible in the body of f must
be that after incrementation.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Michiel Salters
Guest





PostPosted: Tue Aug 26, 2003 6:42 pm    Post subject: Re: Parameter evaluation order? Reply with quote

[email]usenet (AT) carrietech (DOT) com[/email] (Groman) wrote in message news:<ae953bad.0308251024.52d68534 (AT) posting (DOT) google.com>...
Quote:
Hello,

I recently bumped into a relatively interesting problem with a C++
project of mine. After years and years of heavy C++ programming, I'm
surprised that this has never occured to me and I have not discovered
it before. Imagine my surprise when I discovered that function
parameters are not evaluated left-to-right. Now, it makes sense to me
why that is on my platform, but this is not portable behaviour is it?

No, the order of evaluation is very much a choice of the compiler
implementor. It may even vary between functions. E.g. evaluate all
paramters that are passed via the stack, and only then evaluate the
parameters that can be passed in a register. That would make sense,
as you could use the registers as scratch space when evaluating the
stack parameters.
In short, you don't have a clue.

Quote:
i.e. I guess what I am asking is whenever the parameter evaluation
order is defined in any C++ standard or is it considered ambiguous.

For example, say we have a function foo as follows

void foo(int a, int b)
{
std::cout << a << " " << b << " ";
}

and we call it as follows:

int x = 5;
foo(--x, ++x);

Now for all intents and purposes the results will be ambigious. For
all we know, this will run on a parallel machine and both parameter
evaluations will execute in parallel giving foo(4, 6). On a stack
machine, such as an ia32, it might evaluate right to left(and it does
on at least 2 C++ implementations I tried - Borland and Gnu) and it
will be foo(5, 6). And I theorize that on a linear but RISC
register-passing implementation it might become foo(4, 5). After the
function call, x will undoubtebly be 5, however.

No, it won't. The two expressions modify a single variable twice
between sequence points, which is undefined behavior. You assumed
unspecified behavior, which basically means the result is one of
a few reasonable choices. However, your example may cause a CPU
exception terminating your program etcetera.

Regards,
--
Michiel Salters

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Aaron Bentley
Guest





PostPosted: Thu Aug 28, 2003 2:45 pm    Post subject: Re: Parameter evaluation order? Reply with quote

Andrea Griffini wrote:
[snip]
Quote:

What does all this mean ? Just avoid dependence on order
of evaluation of subexpressions Smile ...

The most common error in this area is in my experience
assuming that

std::cout << f() << g() << h();

will call f, then g and last h while this is not guaranteed
at all as those calls can be executed in any order.

I don't get it-- this doesn't seem like an equivalent case to me. While
function parameters may be evaluated in any order, my understanding is
that operators of the same precedence are guaranteed to be evaluated
left-to-right.

To extend your example, f g and h are all types with constructors, right?
And you're saying you could get
(std::cout << f()) << (g() <
right?
Since there is no operator << (g &, h const &), I can't see how this
could work. AFAICT, the whole stream system assumes that << is
evaluated left-to-right. Otherwise, the output state modifiers (like
setting the floating-point precision) couldn't work, and you'd get
errors that operator << (g &, h const &) is undefined.

You have to evaluate operator << (ostream &, f const &) first. Since it
returns ostream&, you can then evaluate operator << (ostream &, const &g).

Conceptually, (((std::cout << f()) << g()) << h()) is the only possible
order. Or were you saying something different?

Aaron

--
Aaron Bentley
www.aaronbentley.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maciej Sobczak
Guest





PostPosted: Fri Aug 29, 2003 11:19 am    Post subject: Re: Parameter evaluation order? Reply with quote

Aaron Bentley wrote:

Quote:
Conceptually, (((std::cout << f()) << g()) << h()) is the only possible
order. Or were you saying something different?

As far as I understand it, the trick is that whereas the *results* of
calling f(), g() and h() will be certainly used in the order shown
above, there is absolutely no requirement on the order of calling these
functions. In other words, compiler can set things up so that f(), g()
and h() will be called in any order it pleases, storing the results
somewhere to be later used in the correct order. If this may help the
compiler doing some optimizations, it is justified.

Another example is this:

i = f() * g() + h();

There is absolutely no requirement that f() and g() are called before
h(), although the *results* of these calls will certainly be used in the
order mandated by operator precedence (first multiplication and then
addition).

--
Maciej Sobczak
http://www.maciejsobczak.com/

Distributed programming lib for C, C++, Python & Tcl:
http://www.maciejsobczak.com/prog/yami/


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Richard Smith
Guest





PostPosted: Fri Aug 29, 2003 11:29 am    Post subject: Re: Parameter evaluation order? Reply with quote

Aaron Bentley wrote:

Quote:
std::cout << f() << g() << h();

To extend your example, f g and h are all types with constructors, right?
And you're saying you could get
(std::cout << f()) << (g() <

No, you can't get that. The associativity of operator<< is
well defined. What can happen, however is

{
return_type_of_f const& f_return = f();
return_type_of_h const& h_return = h(); // Note: order of
return_type_of_g const& g_return = g(); // these reversed
std::cout << f_return << g_return << h_return;
}

Or, indeed, any other ordering of calls to f(), g() and h().
In fact, repeat the line, and you might get different
orderings each time.

--
Richard Smith

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Shay
Guest





PostPosted: Fri Aug 29, 2003 11:31 am    Post subject: Re: Parameter evaluation order? Reply with quote

Aaron Bentley wrote:
Quote:
Andrea Griffini wrote:
[snip]
What does all this mean ? Just avoid dependence on order
of evaluation of subexpressions Smile ...

The most common error in this area is in my experience
assuming that

std::cout << f() << g() << h();

will call f, then g and last h while this is not guaranteed
at all as those calls can be executed in any order.

I don't get it-- this doesn't seem like an equivalent case to me. While
function parameters may be evaluated in any order, my understanding is
that operators of the same precedence are guaranteed to be evaluated
left-to-right.
[snip]
AFAICT, the whole stream system assumes that << is
evaluated left-to-right. Otherwise, the output state modifiers (like
setting the floating-point precision) couldn't work, and you'd get
errors that operator << (g &, h const &) is undefined.
[snip]


std::cout << f() << g() << h();

This results in function calls, due to operator overloading (to improve
readability, operator << is abbreviated as op<<):

op<<( op<<( op<<( std::cout, f() ), g() ), h() );

Simplified:

op( op( op( a, b ), c ), d );

Restricting consideration to evaluating the arguments left-to-right and
right-to-left, with no interleving, here are the orders the expressions
are evaluated:

left to right:
t = a;
t1 = op( t, b );
t2 = op( t1, c );
op( t3, d );

right to left:
t1 = d;
t2 = c;
t3 = b;
t4 = op( a, t3 );
t5 = op( t4, t2 );
op( t5, t1 );

In each version, the function calls are made in the same order, so in the
original context the values are output in the expected order. Order of
evaluation is irrelevant to the function call order since the outer calls
to operator << rely on the results of inner calls. A data flow makes this
clearer:

a --> o
b --> p --> o
c --------> p --> o
d --------------> p ----> result

An efficiency justification for allowing the compiler to choose the order
of evaluation is also evident from the above elaborations.

--
Shay

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Andrea Griffini
Guest





PostPosted: Fri Aug 29, 2003 11:32 am    Post subject: Re: Parameter evaluation order? Reply with quote

On 28 Aug 2003 10:45:56 -0400, Aaron Bentley
<aaron.bentley (AT) utoronto (DOT) ca> wrote:

Quote:
The most common error in this area is in my experience
assuming that

std::cout << f() << g() << h();

will call f, then g and last h while this is not guaranteed
at all as those calls can be executed in any order.

I don't get it-- this doesn't seem like an equivalent case to me. While
function parameters may be evaluated in any order, my understanding is
that operators of the same precedence are guaranteed to be evaluated
left-to-right.

The common mistake is to confuse what is precedence and grouping
with what is order of evaluation. If I write:

f()*g() + h()

for sure the multiplication will be computed before the addition...
but still h() can be the first function being called.
In other words the compiler is allowed to generate code like...

call h() and store result in temp1
call g() and store result in temp2
call f() and store result in temp3
compute temp2*temp3 and store result int temp4
compute temp4+temp1

Quote:
To extend your example, f g and h are all types with constructors, right?
And you're saying you could get
(std::cout << f()) << (g() <
right?

No... the grouping will always be

( (std::cout << f()) << g() ) << h()

but still h() can be the first function being called.

The precedence and grouping just affect in which order
the partial results will be *used*, not the order in
which they will be *computed*.

If you need to impose a specific order then just place
a sequence point...

std::cout << f(); // this ";" implies a sequence point
std::cout << g(); // this ";" implies a sequence point
std::cout << h();

Quote:
Conceptually, (((std::cout << f()) << g()) << h()) is the only possible
order. Or were you saying something different?

It's strange that many don't have any objection that
evaluating "f()*g()+h()" may call h() first, but with
the stream output operation there is some psychological
effect that make that seem a "sequence".

Looks like a sequence but it's not... the only operators
that imply an order of evaluation are "&&", "||" and the
rarely used comma operator "," (and only if they're not
overloaded).

The predefined logical "and" and logical "or" do even
more than that, as they will skip evaluation of the
right (second) term if result is already known; this
is not allowed for other operators... i.e.

int f();

void foo()
{
int x = 0;
int y = x * f(); // This will call f anyway.
...
}

HTH
Andrea

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Aaron Bentley
Guest





PostPosted: Sat Aug 30, 2003 11:37 pm    Post subject: Re: Parameter evaluation order? Reply with quote

Andrea Griffini wrote:

Quote:
The common mistake is to confuse what is precedence and grouping
with what is order of evaluation.
[snip]
the grouping will always be

( (std::cout << f()) << g() ) << h()

but still h() can be the first function being called.

Okay, I get what you're saying now. Thanks.


Aaron
--
Aaron Bentley
www.aaronbentley.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.