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.