vector iterators incompatible while erase from vec

2019-03-02 03:12发布

I have a map which elements are vectors.I have to delete from these vectors all elements which are equal to special number num

std::map<size_t,std::vector<size_t> > myMap;
for (std::map<size_t,std::vector<size_t> >::iterator itMap = myMap.begin();itMap != myMap.end();++itMap )
{
    for (std::vector<size_t>::iterator itVec = itMap->second.begin();itVec != itMap->second.end();)
    {
        auto itNextVec = itVec;
        ++itNextVec;
        if (*itVec == num)
        {
            itMap->second.erase(itVec );
        }
        itVec = itNextVec;
    }
}

The code causes run-time exepssion .In VS - vector iterators incompatible. Can someone point what is the cause for that?

Thanks

4条回答
我只想做你的唯一
2楼-- · 2019-03-02 03:29

Consider either using a different collection class than vector or creating a new vector with the desired items removed rather than removing from existing vector.

查看更多
Evening l夕情丶
3楼-- · 2019-03-02 03:47

erasing will invalidate the iterator

Iterator validity
Iterators, pointers and references pointing to position (or first) and beyond are 
invalidated, with all iterators, pointers and references to elements before position (or 
first) are guaranteed to keep referring to the same elements they were referring to 
before the call.
查看更多
【Aperson】
4楼-- · 2019-03-02 03:47

You can't trivially erase an item from a collection while iterating over it. Think a little about it, your removing what itVec "points" to, after the removal itVec no longer "points" to an element, so it no longer have a "next" pointer.

If you check e.g. this reference, you will see that the erase function returns an iterator to the next element. Continue the loop with this one (without increasing it of course).

查看更多
该账号已被封号
5楼-- · 2019-03-02 03:53

std::vector::erase returns an iterator to the next position of the list, and so when you do an erase you should make your iterator equal to the returned value.

The only thing that you have to consider is that the returned iterator could be the end so you should check for that.

What I personally like to do is is after doing in an erase and I get the next iterator position, I go back to the previous position of the returned iterator and than call a continue on the for loop

Example:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> myInt;
    myInt.push_back(1);myInt.push_back(2);myInt.push_back(3);

    for(auto iter = myInt.begin();
        iter != myInt.end();
        ++iter)
    {
        if(*iter == 1)
        {
            iter = myInt.erase(iter);
            if(iter != myInt.begin())
            {
                iter = std::prev(iter);
                continue;
            }
        }

        std::cout << *iter << std::endl;
    }
}

But doing an erase inside of a iterator loop is frowned upon because it invalidates the old iterator and that could cause a lot of issues if you didn't plan for them.

查看更多
登录 后发表回答