std::cout << x << " " << x++ << std::endl

F

Filipe Sousa

Hi!

Could someone explain to me why this operation is not what I was expecting?

int main()
{
int x = 2;
std::cout << x << " " << x++ << std::endl;
return 0;
}

main.cc: In function 'int main()':
warning: operation on 'x' may be undefined

The result is
3 2

I would expect 2 2.

Thanks
Filipe Sousa
 
K

Kai-Uwe Bux

Filipe said:
Hi!

Could someone explain to me why this operation is not what I was
expecting?

int main()
{
int x = 2;
std::cout << x << " " << x++ << std::endl;

This is equivalent to:

operator<< (
operator<< (
operator<< (
operator<< ( std::cout, x ),
" "
),
x++
),
std::endl;
);

In such an expression, the order of evaluation of subexpressions is
implementation defined. In particular, there is no guarantee that

operator<<( std::cout, x )

will be evaluated before

x++


return 0;
}

main.cc: In function 'int main()':
warning: operation on 'x' may be undefined

The result is
3 2

That is just one possible result.
I would expect 2 2.

That is another possible result.


Best

Kai-Uwe Bux
 
N

n2xssvv g02gfr12930

Filipe said:
Hi!

Could someone explain to me why this operation is not what I was expecting?

int main()
{
int x = 2;
std::cout << x << " " << x++ << std::endl;
return 0;
}

main.cc: In function 'int main()':
warning: operation on 'x' may be undefined

The result is
3 2

I would expect 2 2.

Thanks
Filipe Sousa

The result is undefined for your example. This is because x++ could
compiled to increment after the whole statement or immediately after use
as in this case. In short if you want predictable behaviour when using
operator ++ then the variable it is applied to should only appear once
in the expression being evaluated.

JB
 
K

Kai-Uwe Bux

TB said:

I think, this is *not* a matter of sequence points. The expression is
equivalent to:

operator<< (
operator<< (
operator<< (
operator<< ( std::cout, x ),
" "
),
x++
),
std::endl;
);

and the various function calls provide sufficiently many sequence points.

The results are implementation defined because the evaluation order of the
parameters passed in a function call is implementation defined.


Best

Kai-Uwe Bux
 
B

Ben Bacarisse

The result is undefined for your example. This is because x++ could
compiled to increment after the whole statement or immediately after use
as in this case. In short if you want predictable behaviour when using
operator ++ then the variable it is applied to should only appear once in
the expression being evaluated.

TB's reference to sequence points[1] sits better as a reply to this
remark because, while this is excellent advice for beginners, it is not
entirely true due to expressions like x++ || x++ which have, I think,
predictable behaviour (however daft they may be in practice).

[1]
http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.16
 
J

Jack Klein

The result is undefined for your example. This is because x++ could
compiled to increment after the whole statement or immediately after use
as in this case. In short if you want predictable behaviour when using
operator ++ then the variable it is applied to should only appear once in
the expression being evaluated.

TB's reference to sequence points[1] sits better as a reply to this
remark because, while this is excellent advice for beginners, it is not
entirely true due to expressions like x++ || x++ which have, I think,
predictable behaviour (however daft they may be in practice).

That still has to do with sequence points. The logical operators ||
and && do provide sequence points, so the behavior is well defined.
 
J

Jack Klein

I think, this is *not* a matter of sequence points. The expression is
equivalent to:

operator<< (
operator<< (
operator<< (
operator<< ( std::cout, x ),
" "
),
x++
),
std::endl;
);

and the various function calls provide sufficiently many sequence points.

The results are implementation defined because the evaluation order of the
parameters passed in a function call is implementation defined.

It really still is sequence points. There is no guarantee in the
original expression, or in the expression as you have rewritten it,
that any of the sequence points occurs in between the two accesses of
'x'. The results are undefined for that reason.
 
K

Kai-Uwe Bux

Jack said:
[snip]
I think, this is *not* a matter of sequence points. The expression is
equivalent to:

operator<< (
operator<< (
operator<< (
operator<< ( std::cout, x ),
" "
),
x++
),
std::endl;
);

and the various function calls provide sufficiently many sequence points.

The results are implementation defined because the evaluation order of
the parameters passed in a function call is implementation defined.

It really still is sequence points. There is no guarantee in the
original expression, or in the expression as you have rewritten it,
that any of the sequence points occurs in between the two accesses of
'x'. The results are undefined for that reason.

Thanks for the correction,

I think, I see what you mean. Just to check my understanding: the following
is implementation defined behavior, but not undefined


int post_inc( int & x ) {
int dummy = x;
++x;
return( dummy );
}

operator<< (
operator<< (
operator<< (
operator<< ( std::cout, x ),
" "
),
post_inc( x )
),
std::endl;
);

The reason would be that in the evaluation of sub-expressions one of the
calls operator<<( std::cout, x ) and post_inc( x ) comes first.
Whichever comes first has a sequence point upon return, which separates the
two accesses to x. The reason this does not apply to the original
expression is that x++ is not a function call. Is that correct?


Thanks again

Kai-Uwe Bux
 
B

Ben Bacarisse

In short if you want predictable behaviour when
using operator ++ then the variable it is applied to should only
appear once in the expression being evaluated.

TB's reference to sequence points[1] sits better as a reply to this
remark because, while this is excellent advice for beginners, it is not
entirely true due to expressions like x++ || x++ which have, I think,
predictable behaviour (however daft they may be in practice).

That still has to do with sequence points. The logical operators || and
&& do provide sequence points, so the behavior is well defined.

I thought that is what I had said :/
 
M

Michiel.Salters

Kai-Uwe Bux said:
I think, I see what you mean. Just to check my understanding: the following
is implementation defined behavior, but not undefined


int post_inc( int & x ) {
int dummy = x;
++x;
return( dummy );
}

operator<< (
operator<< (
operator<< (
operator<< ( std::cout, x ),
" "
),
post_inc( x )
),
std::endl;
);

The reason would be that in the evaluation of sub-expressions one of the
calls operator<<( std::cout, x ) and post_inc( x ) comes first.
Whichever comes first has a sequence point upon return, which separates the
two accesses to x. The reason this does not apply to the original
expression is that x++ is not a function call. Is that correct?

Yes, although an easier way to put this is to note that you surrounded
every
x++ by two sequence points, one entering and one leaving post_inc().
Hence
all changes of x must be separated by sequence points.

Michiel Salters
 
K

Kai-Uwe Bux

Yes, although an easier way to put this is to note that you surrounded
every
x++ by two sequence points, one entering and one leaving post_inc().
Hence
all changes of x must be separated by sequence points.

Now, I am confused again: if the post_inc() call "surrounds" x++ by two
sequence points (forcing separation), then: why does operator<<( std::cout,
x) not surround x in the same way (also forcing separation). I am asking
because this is what I was thinking first.


Thanks

Kai-Uwe Bux
 
M

Michiel.Salters

Kai-Uwe Bux said:
Now, I am confused again: if the post_inc() call "surrounds" x++ by two
sequence points (forcing separation), then: why does operator<<( std::cout,
x) not surround x in the same way (also forcing separation). I am asking
because this is what I was thinking first.

Easy: post_inc() must start execution before x++ is executed, and
cannot
finish execution until x++ is executed (once). There are sequence
points
on "both sides of time". On the other hand, in the original example the

only thing you know is that x++ must be called before operator<<.
However,
it can be done arbitrarily early. There is no sequence point that must
be later
than the first x++, but earlier than the second.

In general, sequence point work in both ways: to keep things from
starting
too early, and from finishing too late. But you need two sequence
points
if you need both guarantees.

HTH,
Michiel Salters
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top