Connecting Tech Pros Worldwide Help | Site Map

unexpected result using std::list

Mike Pemberton
Guest
 
Posts: n/a
#1: Jul 19 '05
I'm sure there's a good explanation for this effect, but I get rather
a strange output from this little test:

#include <iostream>
#include <list>

int main()
{
std::list<int> int_list;

int_list.push_back(1);
int_list.push_back(2);
int_list.push_back(3);
int_list.push_back(4);

std::list<int>::reverse_iterator rev = int_list.rbegin();
while(rev != int_list.rend())
{
std::cout << *rev++ << std::endl;
int_list.pop_back(); // This line causes a problem.
}
return 0;
}

Output:
4
3
2
1
0
0

The inclusion of the int_list.pop_back() call seems to cause the two
additional iterations through the loop that print the two extra zeros.
If I comment out the int_list.pop_back() line the output is as
expected, and if i use a different conditional statement such as
while(! int_list.empty()) the output is also as expected.

Does anyone know why this doesn't work? Are there member functions of
std::list that shouldn't be used with iterators, reverse-iterators or
something?

I'm using Red Hat 7 & g++.
tom_usenet
Guest
 
Posts: n/a
#2: Jul 19 '05

re: unexpected result using std::list


On 14 Oct 2003 07:20:15 -0700, mhpemberton@vodafone.net (Mike
Pemberton) wrote:
[color=blue]
>I'm sure there's a good explanation for this effect, but I get rather
>a strange output from this little test:
>
>#include <iostream>
>#include <list>
>
>int main()
>{
> std::list<int> int_list;
>
> int_list.push_back(1);
> int_list.push_back(2);
> int_list.push_back(3);
> int_list.push_back(4);
>
> std::list<int>::reverse_iterator rev = int_list.rbegin();
> while(rev != int_list.rend())
> {
> std::cout << *rev++ << std::endl;
> int_list.pop_back(); // This line causes a problem.[/color]

The above line erases the element that rev is pointing to! Remember
that a reverse iterator's base iterator is actually the iterator to
the element after the one that dereferences. In any case, the above
line invalidates rev, so you can't legally perform any operations on
it, including comparing it to rend, dereferencing it and incrementing
it.
[color=blue]
> }
> return 0;
>}
>
>Output:
>4
>3
>2
>1
>0
>0
>
>The inclusion of the int_list.pop_back() call seems to cause the two
>additional iterations through the loop that print the two extra zeros.
> If I comment out the int_list.pop_back() line the output is as
>expected, and if i use a different conditional statement such as
>while(! int_list.empty()) the output is also as expected.
>
>Does anyone know why this doesn't work? Are there member functions of
>std::list that shouldn't be used with iterators, reverse-iterators or
>something?[/color]

Yes, any list operation that erases an element invalidates all
iterators to that element. A reverse iterator is a strange beast,
since its base iterator is actually the one after the element it
dereferences to.

Tom
Victor Bazarov
Guest
 
Posts: n/a
#3: Jul 19 '05

re: unexpected result using std::list


"Mike Pemberton" <mhpemberton@vodafone.net> wrote...[color=blue]
> I'm sure there's a good explanation for this effect, but I get rather
> a strange output from this little test:
>
> #include <iostream>
> #include <list>
>
> int main()
> {
> std::list<int> int_list;
>
> int_list.push_back(1);
> int_list.push_back(2);
> int_list.push_back(3);
> int_list.push_back(4);
>
> std::list<int>::reverse_iterator rev = int_list.rbegin();
> while(rev != int_list.rend())
> {
> std::cout << *rev++ << std::endl;
> int_list.pop_back(); // This line causes a problem.
> }
> return 0;
> }
>
> Output:
> 4
> 3
> 2
> 1
> 0
> 0
>
> The inclusion of the int_list.pop_back() call seems to cause the two
> additional iterations through the loop that print the two extra zeros.
> If I comment out the int_list.pop_back() line the output is as
> expected, and if i use a different conditional statement such as
> while(! int_list.empty()) the output is also as expected.
>
> Does anyone know why this doesn't work? Are there member functions of
> std::list that shouldn't be used with iterators, reverse-iterators or
> something?[/color]

Not sure off the top of my head, but at the time when you pop_back
the "last" element (at the moment when the list becomes empty), the
'rev' iterator may actually become screwed up.

Although the 'pop_back' is said to invalidate only the iterators and
references to the erased elements, the problem is that when pop_back
empties the list, iterators that used to be the same as the ends of
the list may become not the same any more, I think that's what you
are experiencing here.

For more clarification ask about it in comp.std.c++. FWIW, it could
be a defect in the Standard (the fact that it doesn't specify what
happens to the iterator which _is_ supposedly pointing 'one past the
end'.

Try this:
------------------------------------------------------------------
#include <string>
#include <iostream>
#include <list>
using namespace std;

int main()
{
list<int> int_list;

list<int>::reverse_iterator rev = int_list.rbegin();

cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
<< "the same as 'rend()'\n";

cout << "Pushing '1'...\n";

int_list.push_back(1);

cout << "Resetting 'rev'...\n";

rev = int_list.rbegin();

cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
<< "the same as 'rend()'\n";

cout << "'rev' points to " << *rev++ << std::endl;

cout << "After ++ ";

cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
<< "the same as 'rend()'\n";

cout << "Popping the back\n";
int_list.pop_back(); // This line causes a problem.

cout << "'rev' is " << (rev == int_list.rend() ? "" : "NOT ")
<< "the same as 'rend()'\n";

string s;
getline(cin, s);
}

------------------------------------------------------------------

Victor



Dan Cernat
Guest
 
Posts: n/a
#4: Jul 19 '05

re: unexpected result using std::list


mhpemberton@vodafone.net (Mike Pemberton) wrote in message news:<bcd9b584.0310140620.13baf810@posting.google. com>...[color=blue]
> I'm sure there's a good explanation for this effect, but I get rather
> a strange output from this little test:
>
> #include <iostream>
> #include <list>
>
> int main()
> {
> std::list<int> int_list;
>
> int_list.push_back(1);
> int_list.push_back(2);
> int_list.push_back(3);
> int_list.push_back(4);
>
> std::list<int>::reverse_iterator rev = int_list.rbegin();
> while(rev != int_list.rend())
> {
> std::cout << *rev++ << std::endl;
> int_list.pop_back(); // This line causes a problem.
> }
> return 0;
> }
>
> Output:
> 4
> 3
> 2
> 1
> 0
> 0
>
> The inclusion of the int_list.pop_back() call seems to cause the two
> additional iterations through the loop that print the two extra zeros.
> If I comment out the int_list.pop_back() line the output is as
> expected, and if i use a different conditional statement such as
> while(! int_list.empty()) the output is also as expected.
>
> Does anyone know why this doesn't work? Are there member functions of
> std::list that shouldn't be used with iterators, reverse-iterators or
> something?
>
> I'm using Red Hat 7 & g++.[/color]

pop_back invalidates the iterator. Generally, insertions and deletions
invalidate iterators. I think this is what happens.
Closed Thread