++i++ for iterator in loops (gcc-3.4.4)

  • Thread starter Frank Bergemann
  • Start date
F

Frank Bergemann

Hi,

i stumbled this in source code review:

VALID(?!):
======

frank@frank-desktop:~$ cat test.cc
#include <iostream>
#include <list>

int main()
{
std::list<int> values;
values.push_back(1);
values.push_back(2);
values.push_back(3);
values.push_back(4);
values.push_back(5);
values.push_back(6);
for (std::list<int>::const_iterator i = values.begin();
i != values.end();
++i++) { // ### SEE THIS
std::cout << "i is " << *i << std::endl;
}
return 0;
}

frank@frank-desktop:~$ ./test
i is 1
i is 2
i is 3
i is 4
i is 5
i is 6


NOT VALID:
=======

frank@frank-desktop:~$ cat test.cc
#include <iostream>
#include <list>

int main()
{
for (int i = 1;
i < 7;
++i++) {
std::cout << "i is " << i << std::endl;
}
return 0;
}

doesn't compile:

frank@frank-desktop:~$ g++ -o test test.cc
test.cc: In function »int main()«:
test.cc:8: Fehler: Ungültiger L-Wert in Erhöhung

So why behaves iterator different that integer?

rgds

Frank
 
R

Ron Natalie

Frank said:
Hi,

i stumbled this in source code review:

VALID(?!):


It's undefined behavior for integers.
It's possibly undefined behavior for iterators, but
certainly something that you can't rely on being well
defined.

What is it supposed to do anyhow.

++i, ++i

would be well defined and clearer in intent.
 
J

James Kanze

i stumbled this in source code review:

No.

frank@frank-desktop:~$ cat test.cc
#include <iostream>
#include <list>

int main()
{
std::list<int> values;
values.push_back(1);
values.push_back(2);
values.push_back(3);
values.push_back(4);
values.push_back(5);
values.push_back(6);
for (std::list<int>::const_iterator i = values.begin();
i != values.end();
++i++) { // ### SEE THIS

This is ++ (i ++). The result of i ++ is not an lvalue, and the
standard doesn't require prefix ++ to work on non-lvalues. If
the iterator is a class type (almost certainly the case for
std::list, but not a formal requirement---and implementations
have used a simple T* for std::vector), and the prefix operator
++ is a member function (often the case, but it could just as
easily be a free function), then the code will compile, calling
prefix ++ on the temporary which is returned from the postfix
++, which effectively makes the prefix incrementation a no-op.
(The temporary is destructed at the end of the full expression.)
std::cout << "i is " << *i << std::endl;
}
return 0;
}
frank@frank-desktop:~$ ./test
i is 1
i is 2
i is 3
i is 4
i is 5
i is 6

As you can see, only one incrementation is taken into account.
The prefix ++ increments a temporary, which is then destructed.
NOT VALID:
=======
frank@frank-desktop:~$ cat test.cc
#include <iostream>
#include <list>
int main()
{
for (int i = 1;
i < 7;
++i++) {
std::cout << "i is " << i << std::endl;
}
return 0;
}
doesn't compile:

frank@frank-desktop:~$ g++ -o test test.cc
test.cc: In function »int main()«:
test.cc:8: Fehler: Ungültiger L-Wert in Erhöhung
So why behaves iterator different that integer?

Because in this case, the iterator is a class type, and the
implementation has chosen to make the prefix operator++ a member
function. Neither is required by the standard. The code might
compile, or it might not. And because it is undefined behavior,
it might do anything if it compiles, although in practice, I
can't imagine anything other than what you are seeing: prefix ++
being called on a temporary.
 
J

James Kanze

It's undefined behavior for integers.

It requires a diagnostic for integers (and other non-class
types). The only time it doesn't require a diagnostic is if the
iterator is a class type, and prefix ++ is a member function.
It's possibly undefined behavior for iterators, but
certainly something that you can't rely on being well
defined.

It's always undefined behavior for iterators---the standard (at
least the latest draft, but I don't think that there've been any
changes here) only requires ++ (prefix or postfix) to work on an
lvalue. And any time you violate the constraints of a standard
function, you have undefined behavior. (Which, of course, may
appear to work.
What is it supposed to do anyhow.
would be well defined and clearer in intent.

That's not what it does. I rather suspect that it is just a
typo. The original code was probably just "i++", someone went
on a misguided attempt to convert all of the postfix to prefix,
and after adding the prefix, forgot to delete the postfix.

If this is the case, it does provide two interesting lessons in
softare engineering:

-- Requiring all incrementation to be prefix isn't a good idea
if you already have code where it is postfix, regardless of
what some people clain.

-- It's a good example of an error which slips through testing,
and of why good code review is necessary.
 

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,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top