Thread: Iterator not incrementable?

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    110

    Iterator not incrementable?

    So I am trying to write up two versions of a function, that takes in a list of data structure of students(which consists of their name and grades), and filters out all the failing students, and returns me back the list with only passing students.

    One method simply erases the student from the list.

    Code:
    students extract_fails(students& studs){
    	students fail;
    
    	for(students::iterator i = studs.begin(); i != studs.end(); i++){
    		if(!fgrade(*i)){
    			fail.push_back(*i);
    			studs.erase(i);
    		}
    	}
    
    	return fail;
    }
    The other pushes all passing students to the beginning and resizes the list to the amount of passing students. The one I just mentioned works, but the one I posted up there doesn't. I get back an error saying the iterator is not incrementable. Why is this? Am I improperly erasing the element from the list?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by dnguyen1022
    Am I improperly erasing the element from the list?
    You probably are by failing to account for the invalidation of the iterator. What container are you using?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I don't know if there is an algorithm that both removes and moves the erased elements to a different container, but this could be a task for partition/stable_partition which separates the students within a container. You can then cut out the failed students and put them in a different container (with std::list splice can be used for that).

    Code:
    typedef std::list<Student> StudentList;
    StudentList extract_failed(StudentList& students)
    {
        StudentList failed_students;
        StudentList::iterator it = std::stable_partition(students.begin(), students.end(), passes);
        failed_students.splice(failed_students.end(), students, it, students.end());
        return failed_students;
    }
    If you want to go with a hand-rolled loop, you have to keep in mind that erase() (usually) returns the next valid iterator, and you should do ++iterator only in case you didn't erase the current item.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  4. #4
    Registered User
    Join Date
    Nov 2008
    Posts
    110

    Talking

    I am using a list for the container.

    As for your suggestion anon with the loop, I tried decrementing the iterator everytime i erased the element from the list, but it gives me an error saying the iterator is not decrementable. Your splice suggestion works great, but I would like to get this method working too!

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by dnguyen1022
    As for your suggestion anon with the loop, I tried decrementing the iterator everytime i erased the element from the list, but it gives me an error saying the iterator is not decrementable. Your splice suggestion works great, but I would like to get this method working too!
    By the time to try and decrement the iterator, it is already invalid. The erase member function for sequential containers return the iterator after the end of the point of erasure, so you can assign the return value of erase to your iterator object:
    Code:
    for (students::iterator i = studs.begin(); i != studs.end();) {
        if (!fgrade(*i)) {
            fail.push_back(*i);
            i = studs.erase(i);
        } else {
            ++i;
        }
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Nov 2008
    Posts
    110
    Thank you laserlight. it worked brilliantly!

Popular pages Recent additions subscribe to a feed