return i++

D

DaKoadMunky

cout << i++ << i++; // no, no

I am thinking that this is unspecified behavior rather than undefined given
that the statement is really...

operator<<(operator<<(cout,i++)),i++);

The output is unspecified behavior but the modifications to i are separated by
sequence points and thus do not lead to undefined behavior.

Can anyone confirm or deny this?
 
C

chris

Patrick said:
Don´t bother me. Copy paste. :)




Should be:

int foo()
{
static int i = 0;
return i++;
}

could be perhaps:

const int & foo()
{
static int i = 0;
return i++;
}

but I think there is no big difference....

In that second one you are returning a reference to a temporary (the
temporary made when you post-increment i). Thats a big no-no! Of course,
even if it was a pre-increment you would still be returning a reference
to a local variable, which is still a bad idea :)

Chris
 
R

Rob Williscroft

DaKoadMunky wrote in in comp.lang.c++:
I am thinking that this is unspecified behavior rather than undefined
given that the statement is really...

operator<<(operator<<(cout,i++)),i++);

The output is unspecified behavior but the modifications to i are
separated by sequence points and thus do not lead to undefined
behavior.

Can anyone confirm or deny this?

Not as I understand it, the first i++ needs to be evaluated before the
the first (inner) function call (because of its sequence point) and the
second i++ before the second (outer) function call (again because of its
sequence point).

But nothing say's that both i++'s can't be evaluated before the first
(inner) function call and hence before the first sequence point.

IOW there isn't a sequence point between the two i++'s as is needed
for defined behavior.

Also they can be evaluated in any order (as if the sequence point
problem wasn't bad enough :).

This on the other hand:

int i = 0;

int f( int r )
{
++i;
return r;
}

int main()
{
f( i++ );
}

Has defined behaviour, the sequence point before the function call
ensures that 'i' is updated *before* the call is made so f() returns
0, and 'i' gets the value 2.

Rob.
 
D

DaKoadMunky

Of course,
even if it was a pre-increment you would still be returning a reference
to a local variable, which is still a bad idea :)

But it is a static local.

Doesn't that make it safe?
 
A

Andrey Tarasevich

DaKoadMunky said:
But it is a static local.
Doesn't that make it safe?

'i' is indeed a static local. But the result of 'i++' has nothing to do
with 'i' itself. The result of 'i++' is an rvalue holding the old value
of 'i', which means that a temporary object will be created to
initialize a reference. Returning such a reference is not safe.
 
D

DaKoadMunky

'i' is indeed a static local. But the result of 'i++' has nothing to do
with 'i' itself. The result of 'i++' is an rvalue holding the old value
of 'i', which means that a temporary object will be created to
initialize a reference. Returning such a reference is not safe.

I understand that (although it was not apparent to me immediately.)

The person I had responded to said...

"even if it was a pre-increment you would still be returning a reference
to a local variable"

static int i = 0;
return ++i;

Doesn't pre-increment return a modifiable lvalue that is in fact the operand i?
If so, wouldn't that make the person I was responding to incorrect?
 
R

Ron Natalie

DaKoadMunky said:
I am thinking that this is unspecified behavior rather than undefined given
that the statement is really...

operator<<(operator<<(cout,i++)),i++);

The output is unspecified behavior but the modifications to i are separated by
sequence points and thus do not lead to undefined behavior.

Can anyone confirm or deny this?

The mods are not necessarily separated by sequence points. The i++ expressions
may be evaluated beforfe any of the operator<< functinos are called.
 
A

Andrey Tarasevich

DaKoadMunky said:
I understand that (although it was not apparent to me immediately.)

The person I had responded to said...

"even if it was a pre-increment you would still be returning a reference
to a local variable"

static int i = 0;
return ++i;

Doesn't pre-increment return a modifiable lvalue that is in fact the operand i?
If so, wouldn't that make the person I was responding to incorrect?

In that case you are right. Sorry, I missed that you were specifically
talking about pre-increment. Result of pre-increment is an lvalue
referring to the original variable 'i', which is indeed static local.
There's no immediate problem with returning a reference to it.
 
P

Patrick Kowalzick

This is what my compiler tells me:

int & foo()
{
static int i = 0;
return ++i;
}
// compiles fine

int & foo()
{
static int i = 0;
return i++;
}
// error C2440: 'return' : cannot convert from 'int' to 'int &'
// A reference that is not to 'const' cannot be bound to a non-lvalue

const int & foo()
{
static int i = 0;
return i++;
}
// warning C4172: returning address of local variable or temporary

Regards,
Patrick
 
K

Karl Heinz Buchegger

DaKoadMunky said:
I am thinking that this is unspecified behavior rather than undefined given
that the statement is really...

operator<<(operator<<(cout,i++)),i++);

The output is unspecified behavior but the modifications to i are separated by
sequence points and thus do not lead to undefined behavior.

Can anyone confirm or deny this?

Actually I once walked through all of this in the standard.
The point is:
There are 2 different forms of op<<
1) member functions of the stream
2) standalone functions

All the op<< for builtin types (int, char, long, etc...) are
member functions. Thus

cout << i++ << i++;

is equivalent to

cout.op<<( i++ ).op<<( i++ );

because i++ is of type int in both cases.

Hack I can't remember all the details, but they turned around how
function calls are handled. Which one is done first:
the evaluation of the function to call or the evaluation of the
arguments. Search google for an indepth analysis of that.
 
J

JKop

int foo(int i)
{
return i++;
}

should be:

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


should be:

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


and maybe return that by reference too...


-JKop
 
A

Arijit

The ++Patrick-- got me thinking. Is any of the following legal ?

int i;

(i++)++;
++(i++);
(++i)++;
++(++i);

What happens if I omit the parnethesis ?

My guess is (++i)++ and ++(++i) is legal, because ++i is l-value.

One more thing, where can I find a little detailed information on sequence
points ? All I seem to get is very sketchy.

-Arijit
 
A

Andrey Tarasevich

Arijit said:
The ++Patrick-- got me thinking. Is any of the following legal ?

What do you mean by "legal"? Well-formed? Behavior is defined?
int i;

(i++)++;

Ill-formed. Post-increment expects an lvalue.

Ill-formed. Pre-increment expects an lvalue.
(++i)++;
++(++i);

Both well-formed, but produce undefined behavior.
What happens if I omit the parnethesis ?

'(++i)++' without parenthesis is equivalent to '++(i++)'. Others won't
change at all.
My guess is (++i)++ and ++(++i) is legal, because ++i is l-value.

Both are well-formed, but broken, since they produce undefined behavior.
 
A

Arijit

But it is a static local.

Doesn't that make it safe?

Safe in the sense that you will be accessing a defined location in memory.
But it is very unsafe in the sense that the static variable will be
available to modify by anyone who wishes to. You might as well make it
global. In short, never return a reference or pointer to a static local
variable.

-Arijit
 
H

Howard

JKop said:
should be:

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

Not according to the original post, which was asking if it was ok to
post-increment, expecting the returned value to be the value prior to the
increment. Your version would return the value AFTER the increment, which
isn't what was wanted.
and maybe return that by reference too...

No need to do that, I think. It's just an integer, and wouldn't save any
time or memory doing so, would it?


--Howard
 
J

JKop

Howard posted:
Not according to the original post, which was asking if it was ok to
post-increment, expecting the returned value to be the value prior to
the increment. Your version would return the value AFTER the
increment, which isn't what was wanted.


No need to do that, I think. It's just an integer, and wouldn't save
any time or memory doing so, would it?


--Howard


You're right, my bad.


-JKop
 

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,813
Messages
2,569,697
Members
45,488
Latest member
MohammedHa

Latest Threads

Top