Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Unpredictable nature of increment operators

Reply
Thread Tools

Unpredictable nature of increment operators

 
 
bintom
Guest
Posts: n/a
 
      05-09-2008
Why doe the following C++ code behaves as it does?

int i;

i=1; cout << (++i)++; Output: 2
i=1; cout << ++(++i); Output: 3
i=1; cout << (i++)++; Output: Error. LValue required
i=1; cout << ++(i++); Output: Error. LValue required
 
Reply With Quote
 
 
 
 
Ian Collins
Guest
Posts: n/a
 
      05-09-2008
bintom wrote:

Once is enough!

--
Ian Collins.
 
Reply With Quote
 
 
 
 
Martin York
Guest
Posts: n/a
 
      05-09-2008
On May 8, 5:16 pm, bintom <(E-Mail Removed)> wrote:
> Why doe the following C++ code behaves as it does?
>
> int i;
>
> i=1; cout << (++i)++; Output: 2
> i=1; cout << ++(++i); Output: 3
> i=1; cout << (i++)++; Output: Error. LValue required
> i=1; cout << ++(i++); Output: Error. LValue required


Because code like that is so hard to read you would never actually
write it!

Also remember that it is illegal to modify a variable more than once
within the same expression [undefined behavior I believe](somebody
with a copy of the standard will be able to quote you chapter an verse
and the actual definition rather than my layman's wording).
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-10-2008
On 9 mai, 19:21, "Victor Bazarov" <(E-Mail Removed)> wrote:
> Martin York wrote:
> > On May 8, 5:16 pm, bintom <(E-Mail Removed)> wrote:
> >> Why doe the following C++ code behaves as it does?


> >> int i;


> >> i=1; cout << (++i)++; Output: 2
> >> i=1; cout << ++(++i); Output: 3
> >> i=1; cout << (i++)++; Output: Error. LValue
> >> required i=1; cout << ++(i++); Output: Error.
> >> LValue required


> > Because code like that is so hard to read you would never actually
> > write it!


> > Also remember that it is illegal to modify a variable more
> > than once within the same expression [undefined behavior I
> > believe](somebody with a copy of the standard will be able
> > to quote you chapter an verse and the actual definition
> > rather than my layman's wording).


> Only a variable of a built-in type,


No. The rule holds for all types.

I think what is confusing you is the fact that if operator++ is
user defined for the type of x, the expression ++x doesn't
modify x; it calls a function (which might modify x---but that's
a different issue, because the modification doesn't take place
in this expression, and there are sequenece points when calling
or returning from a function).

In the case of operator++, of course, the operator is only
defined for built-in types, so any other type will involve a
function call. This isn't true for all operators, however.

> and only if there is no sequence point between the
> modifications.


That's the key point: whether or not there is a sequence point.

> For example, it's not undefined behaviour to do


> f(i++) + ++i;


Yes it is, since there is no sequence point between the two
incrementations. Sequence points only define a partial
ordering: there is a sequence point before calling f, but that
only establishes and ordering between i++ and the call to f; it
doesn't establish any ordering between the two incrementations.

> IIRC, but the results are unspecified. And if your class has
> the operators ++() or ++(int) overloaded, the results are even
> well-defined and predictable.


They're never well-defined and predictable. The compiler can
call the functions in any order that it wants.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
Jerry Coffin
Guest
Posts: n/a
 
      05-10-2008
In article <g0216m$pqc$(E-Mail Removed)>, http://www.velocityreviews.com/forums/(E-Mail Removed)
says...

[ ... ]

> For example, it's not undefined behaviour to do
>
> f(i++) + ++i;
>
> IIRC, but the results are unspecified.


I believe this still gives undefined behavior. There are three sequence
points in this expression: before f is called, when f returns, and at
the end of the expression. The compiler can generate code that evaluates
the pre-increment, then the post-increment, then the function call.
There's no sequence point between the pre- and post-increment, so the
result is undefined behavior.

> And if your class has the
> operators ++() or ++(int) overloaded, the results are even well-
> defined and predictable. For 'int' they aren't...


Well-defined but not necessarily predictable. The fact that it's a
function call imposes a sequence point as the function is called, and as
it returns -- but still doesn't require that the functions be called in
any particular order, so the value as the function is entered can be
unpredictable. For example:

#include <iostream>

class X {
int value;
public:
X() : value(0) {}
X(int v) : value(v) {}
X &operator++() {
++value;
return *this;
}
X operator+(X const &other) {
return X(value + other.value);
}
friend std:stream &operator<<(std:stream &os, X const &x) {
return os << x.value;
}
};

int main() {
X x, left, right;
std::cout << (left= ++x) + (right = ++x) << "\n";
std::cout << "Left = " << left << "\n";
std::cout << "Right = " << right << "\n";
return 0;
}

Now, this gives defined behavior -- regardless of the order of
evaluation, there is always a sequence point between executing the two
increment operators. Nonetheless, the compiler is free to produce code
that evaluates either the left or the right sub-expression first, so the
values of 'left' and 'right' aren't entirely predictable.

For example, using Comeau, I get Left = 1 and Right = 2. Using G++ or
Microsoft, I get Left = 2 and Right = 1.

--
Later,
Jerry.

The universe is a figment of its own imagination.
 
Reply With Quote
 
Jerry Coffin
Guest
Posts: n/a
 
      05-10-2008
In article <d16e4f6a-c4f2-4b6f-bf7d-
(E-Mail Removed)>, (E-Mail Removed)
says...
> On 9 mai, 19:21, "Victor Bazarov" <(E-Mail Removed)> wrote:


[ ... ]

> > For example, it's not undefined behaviour to do

>
> > f(i++) + ++i;

>
> Yes it is, since there is no sequence point between the two
> incrementations. Sequence points only define a partial
> ordering: there is a sequence point before calling f, but that
> only establishes and ordering between i++ and the call to f; it
> doesn't establish any ordering between the two incrementations.


I believe it establishes _some_ ordering, but not enough[1]. In
particular, I believe the compiler is required to treat evaluation of a
function argument and calling the function as atomic -- i.e. once the
evaluation of any argument takes place, it must proceed to evaluated the
other arguments (if any) and then call the function.

In the expression above, I don't believe it's allowed for the post-
increment to be evaluated, then the pre-increment, then the function
call. It is, however, allowed for the pre-increment, then the post-
increment, then the function call -- and in this ordering, there is no
sequence point between the pre-increment and the post-increment, so the
result is undefined behavior.

1: Though it's open to some question. $1.9/8 says: "Once the execution
of a function begins, no expressions from the calling function are
evaluated until execution of the called function has completed."

I'm interpreting evaluating the arguments to a function as part of
execution of the function. If you choose to interpret it as a completely
separate act that happens before the function's execution, then you're
right -- no ordering is defined. At least in this case, it doesn't make
any real difference though -- the overall result is undefined behavior
either way.

--
Later,
Jerry.

The universe is a figment of its own imagination.
 
Reply With Quote
 
Bo Persson
Guest
Posts: n/a
 
      05-11-2008
Jerry Coffin wrote:
> In article <d16e4f6a-c4f2-4b6f-bf7d-
> (E-Mail Removed)>, (E-Mail Removed)
> says...
>> On 9 mai, 19:21, "Victor Bazarov" <(E-Mail Removed)> wrote:

>
> [ ... ]
>
>>> For example, it's not undefined behaviour to do

>>
>>> f(i++) + ++i;

>>
>> Yes it is, since there is no sequence point between the two
>> incrementations. Sequence points only define a partial
>> ordering: there is a sequence point before calling f, but that
>> only establishes and ordering between i++ and the call to f; it
>> doesn't establish any ordering between the two incrementations.

>
> I believe it establishes _some_ ordering, but not enough[1]. In
> particular, I believe the compiler is required to treat evaluation
> of a function argument and calling the function as atomic -- i.e.
> once the evaluation of any argument takes place, it must proceed to
> evaluated the other arguments (if any) and then call the function.
>
> In the expression above, I don't believe it's allowed for the post-
> increment to be evaluated, then the pre-increment, then the function
> call. It is, however, allowed for the pre-increment, then the post-
> increment, then the function call -- and in this ordering, there is
> no sequence point between the pre-increment and the post-increment,
> so the result is undefined behavior.
>
> 1: Though it's open to some question. $1.9/8 says: "Once the
> execution of a function begins, no expressions from the calling
> function are evaluated until execution of the called function has
> completed."
>
> I'm interpreting evaluating the arguments to a function as part of
> execution of the function. If you choose to interpret it as a
> completely separate act that happens before the function's
> execution, then you're right -- no ordering is defined. At least in
> this case, it doesn't make any real difference though -- the
> overall result is undefined behavior either way.


I think your second interpretation is the correct one. It means that
++i can be evalueated before or after calling f, but not during.

However, evaluating the arguments is done before calling the function,
not as part of the call.

Breaking it down:

evaluating i++
sequence point
call function
return
sequence point
add


At the point of the add operation, the result of the right hand side
of the addition must be available. It must be evaluated somewhere
before the add operation, obviously, but not between the two sequence
points.



Bo Persson


 
Reply With Quote
 
Old Wolf
Guest
Posts: n/a
 
      05-11-2008
On May 11, 3:01 am, Jerry Coffin <(E-Mail Removed)> wrote:
> > On 9 mai, 19:21, "Victor Bazarov" <(E-Mail Removed)> wrote:
> > > For example, it's not undefined behaviour to do
> > > > f(i++) + ++i;

>
> I believe the compiler is required to treat evaluation of a
> function argument and calling the function as atomic -- i.e. once the
> evaluation of any argument takes place, it must proceed to evaluated the
> other arguments (if any) and then call the function.


There is no such requirement. In the following code,
for example,:
foo( bar(), baz() ) + qux();

the order of calling functions could be:
baz, qux, bar, foo.

or any other ordering, so long as 'foo' comes after
both 'bar' and 'baz'.

The code of Victor Bazarov causes undefined behaviour
if 'i' is a builtin type, because there might not be
a sequence point between the two modifications of 'i'.
 
Reply With Quote
 
Jerry Coffin
Guest
Posts: n/a
 
      05-11-2008
In article <(E-Mail Removed)>, (E-Mail Removed) says...

[ ... ]

> > 1: Though it's open to some question. $1.9/8 says: "Once the
> > execution of a function begins, no expressions from the calling
> > function are evaluated until execution of the called function has
> > completed."
> >
> > I'm interpreting evaluating the arguments to a function as part of
> > execution of the function. If you choose to interpret it as a
> > completely separate act that happens before the function's
> > execution, then you're right -- no ordering is defined. At least in
> > this case, it doesn't make any real difference though -- the
> > overall result is undefined behavior either way.

>
> I think your second interpretation is the correct one. It means that
> ++i can be evalueated before or after calling f, but not during.


You could _certainly_ be right. As I said, in this case it doesn't
really make much difference, since either one gives undefined results.

I got curious and read through N2284, and found that the wording has
been changed to [intro.execution]/16:

Every evaluation in the calling function (including other
function calls) that is not otherwise specifically
sequenced before or after the execution of the body of
the called function is indeterminately sequenced with
respect to the execution of the called function.

This is apparently an attempt at clarifying the situation, but doesn't
seem (to me) to add much clarity. In particular, it specifically cites
execution of the body of the function in one place, but execution of the
called function in the other. It's not at all clear whether this is just
mildly sloppy wording, and the two are intended to be synonymous, or
whether it's completely intentional, and intended to delineate between
the two.

--
Later,
Jerry.

The universe is a figment of its own imagination.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-11-2008
On 10 mai, 17:01, Jerry Coffin <(E-Mail Removed)> wrote:
> In article <d16e4f6a-c4f2-4b6f-bf7d-
> (E-Mail Removed)>,
> (E-Mail Removed) says...


> > On 9 mai, 19:21, "Victor Bazarov" <(E-Mail Removed)> wrote:


> [ ... ]


> > > For example, it's not undefined behaviour to do


> > > f(i++) + ++i;


> > Yes it is, since there is no sequence point between the two
> > incrementations. Sequence points only define a partial
> > ordering: there is a sequence point before calling f, but
> > that only establishes and ordering between i++ and the call
> > to f; it doesn't establish any ordering between the two
> > incrementations.


> I believe it establishes _some_ ordering, but not enough[1].
> In particular, I believe the compiler is required to treat
> evaluation of a function argument and calling the function as
> atomic -- i.e. once the evaluation of any argument takes
> place, it must proceed to evaluated the other arguments (if
> any) and then call the function.


Where do you get that? I've used compilers which violate it,
and I'm fairly sure that it is neither required by the standard,
nor was it the intent. There was even a DR for C, the answer of
which made it quite clear that the only reordering which isn't
allowed is intervening the actual execution of the function with
other parts of the expression.

> In the expression above, I don't believe it's allowed for the
> post- increment to be evaluated, then the pre-increment, then
> the function call. It is, however, allowed for the
> pre-increment, then the post- increment, then the function
> call -- and in this ordering, there is no sequence point
> between the pre-increment and the post-increment, so the
> result is undefined behavior.


> 1: Though it's open to some question. $1.9/8 says: "Once the
> execution of a function begins, no expressions from the
> calling function are evaluated until execution of the called
> function has completed."


> I'm interpreting evaluating the arguments to a function as
> part of execution of the function.


That's the first time I've heard that interpretation. The
classical example of undefined behavior in C is:
f( i++ ) + f( i ++ )

> If you choose to interpret it as a completely separate act
> that happens before the function's execution, then you're
> right -- no ordering is defined. At least in this case, it
> doesn't make any real difference though -- the overall result
> is undefined behavior either way.


In practice, I'd say that if you have to ask the question, the
code is probably doing something it shouldn't anyway. For
readability's sake, even if it is defined. But the classical
interpretation, at least within the C committee (many years ago)
was that the execution of the function is what happens between
the sequence point entering the function, and the sequence point
leaving it.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Post increment ++ has higher precedence than pre increment ++. Why? Alf P. Steinbach /Usenet C++ 0 05-22-2011 12:03 PM
why prefix increment is faster than postfix increment? jrefactors@hotmail.com C++ 99 06-11-2010 12:51 PM
post increment or pre increment? Peng Yu Perl Misc 7 11-23-2008 11:44 PM
Unpredictable result of Increment operation bintom C++ 9 05-10-2008 03:37 PM
why prefix increment is faster than postfix increment? jrefactors@hotmail.com C Programming 104 10-27-2005 11:44 PM



Advertisments