std::list::erase() error during runtime

Started by
2 comments, last by Arjan B 16 years, 3 months ago
I'm working my way through C++ Primer (4th edition) and I stumbled upon an error while trying one of the exercises that I don't understand. The following code works fine but when I uncomment the commented part, I get an error during runtime.

#include <iostream>
#include <list>
#include <vector>

using std::vector;
using std::list;
using std::cout;
using std::cin;
using std::endl;

int main()
{
  int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
  size_t size = sizeof(ia)/sizeof(int);
  
  // intialize vector and list with values in array
  vector<int> iVec(ia, ia + size);
  list<int>   iList(ia, ia + size);
  
  // erase all the even numbers in vector
  for (vector<int>::iterator i = iVec.begin(); i != iVec.end(); i++)
    if (*i % 2 == 0)
      iVec.erase(i);
  
  // supposed to erase all odd numbers in list
  /*
  for (list<int>::iterator i = iList.begin(); i != iList.end(); i++)
    if (*i % 2 == 1)
      iList.erase(i);
  */
  
  // show vector
  cout << "Vector: " << endl;
  for (vector<int>::const_iterator i = iVec.begin(); i != iVec.end(); i++)
    cout << *i << endl;
  
  cout << endl;
  
  // show list
  cout << "List: " << endl;
  for (list<int>::const_iterator i = iList.begin(); i != iList.end(); i++)
    cout << *i << endl;
    
  cout << endl;
  
  system("pause");
  
  return 0;
}


I think it has something to do with deleting the last element but I might be all wrong ^^. So maybe anyone here can tell me what I'm doing wrong? Thank you in advance.
Advertisement
Deleting from a sequence container invalidates your iterator.

You'll notice that std::list::erase(), returns another iterator that you can use to continue iteration. However, in your code you simply ignore the return value. Ignoring a return value in C++ is a no-op, not an error. So it went unflagged.
When you erase an element from a sequence the iterator that pointed to that element is invalidated, therefore incrementing that iterator to access the next element is an unsafe operation.

It's working with the vector because a vector is guarenteed to be contiguous and the easiest implementation of a vector iterator is just a pointer; it's not guarenteed to work, it just happens to.
As for a list, the iterators are more complex and the elements aren't contiguous; furthermore the iterator may even get nullified when it's element is erased. So it's well and truly a dead iterator.

You'll notice however that the erase method actually returns an iterator, the iterator it returns points to the next (valid) element in the container. So rather than incrementing the invalidated iterator just grab the next one from the return of erase.
Ah thanks :D!

// erase all the even numbers in vector  for (vector<int>::iterator i = iVec.begin(); i != iVec.end();)    if (*i % 2 == 0)      i = iVec.erase(i);    else      i++;    // erase all the odd numbers in list  for (list<int>::iterator i = iList.begin(); i != iList.end();)    if (*i % 2 == 1)      i = iList.erase(i);    else      i++;

This topic is closed to new replies.

Advertisement