Connecting Tech Pros Worldwide Help | Site Map

unexpected result using std::list

 
LinkBack Thread Tools Search this Thread
  #1  
Old July 19th, 2005, 07:12 PM
Mike Pemberton
Guest
 
Posts: n/a
Default unexpected result using std::list

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++.

  #2  
Old July 19th, 2005, 07:12 PM
tom_usenet
Guest
 
Posts: n/a
Default 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
  #3  
Old July 19th, 2005, 07:13 PM
Victor Bazarov
Guest
 
Posts: n/a
Default 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



  #4  
Old July 19th, 2005, 07:13 PM
Dan Cernat
Guest
 
Posts: n/a
Default 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.
 

Bookmarks

Thread Tools Search this Thread
Search this Thread:

Advanced Search

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 Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

Popular Articles

What is Bytes?

We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights. Get the best answers to your questions from over 220,989 network members.