unexpected result using std::list

M

Mike Pemberton

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

tom_usenet

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.

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.
}
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?

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
 
V

Victor Bazarov

Mike Pemberton said:
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?

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);
}
 
D

Dan Cernat

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

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

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top