Sign in to follow this  
Arjan B

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

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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++;

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this