13

Possible Duplicates:
Vector.erase(Iterator) causes bad memory access
iterate vector, remove certain items as I go.

Hi, I wrote this but I am get some errors when running it

for (vector< vector<Point> >::iterator track = tracks_.begin(); track != tracks_.end(); track++) {
        if (track->empty()) { // if track is empty, remove it
            tracks_.erase(track);
            track++; // is this ok?
        }else {   //if there are points, deque
            track->erase(track->begin()); //my program crashes here after a while... ;(
        }
    }

I have a vector of vector of points (2 ints) whose I call tracks (1 track is 1 vector of points) I want to check each track and if they contain points then delete the first one otherwise delete the track. Is this correct?

Thanks in advance.

Community
  • 1
  • 1
nacho4d
  • 43,720
  • 45
  • 157
  • 240
  • This kind of question has already been asked many times. The first result of searching for "C++ erase iterator" is http://stackoverflow.com/questions/2943912/vector-eraseiterator-causes-bad-memory-access which answers this question too. – TheUndeadFish Oct 10 '10 at 17:41
  • @nacho4d: Not directly related, but take a look at Boost MultiArray for two-dimensional structures. It is somewhat easier to use than a ` std::vector >` type. –  Oct 10 '10 at 17:44
  • @TheUndeadFish: If this is so simple, why don't you (simply) _vote to close_ this question as a duplicate?? – sbi Oct 10 '10 at 17:49
  • @nacho4d you should name a functor (or create a function named) `ShiftIfNonEmpty`. Sometimes if you give further thought before naming your things you see the expense of the operation. – wilhelmtell Oct 10 '10 at 18:19
  • @sbi Unless I've missed something, I don't believe I am yet able to vote to close with my current reputation. So I tried to contribute what I could with a comment. – TheUndeadFish Oct 10 '10 at 18:21
  • @TheUndeadFish: Oh, you're right! I'm sorry I missed that. – sbi Oct 10 '10 at 18:50
  • Relax, exact duplicate police. This question is titled better. – bobobobo Jun 02 '11 at 22:59

2 Answers2

42

A vector's erase() invalidates existing iterators, but it returns a new iterator pointing to the element after the one that was removed. This returned iterator can be used to continue iterating over the vector.

Your loop could be written like this:

vector< vector<Point> >::iterator track = tracks_.begin();
while (track != tracks_.end()) {
    if (track->empty()) {
        // if track is empty, remove it
        track = tracks_.erase(track);
    }
    else {
        //if there are points, deque
        track->erase(track->begin());
        ++track;
    }
}
sth
  • 222,467
  • 53
  • 283
  • 367
  • Awesome. Robust, simple, doesn't require making my own delegate, etc. – Eliot May 09 '13 at 21:27
  • This is a common enough pattern that it would be nice to see something like this appear in std. – jbruni Aug 07 '14 at 19:01
  • What does the 2nd "deque" `erase` do? The iterator "track" doesn't even has a erase/begin method? Can't compile it and works well without. – kungfooman Dec 18 '16 at 07:28
  • 1
    @lama12345 this comes directly from the code in the question and works because OP uses a vector of vectors. OP just wanted to do that if `!track->empty()`, it's not directly related to the "delete while iterating" problem. – sth Dec 18 '16 at 15:52
2

I'm not sure what errors you're getting, but chances are that you're invalidating your iterator.

You should read http://www.angelikalanger.com/Conferences/Slides/CppInvalidIterators-DevConnections-2002.pdf

Specifically, vector::erase invalidates all iterator and references to elements after position or first.

David Titarenco
  • 32,662
  • 13
  • 66
  • 111