Why is this vector iterator not incrementable?

2019-01-21 20:35发布

问题:

I'm trying to delete the vector's content and I'm getting an error - vector iterator is not incrementable, why is that?

This is my destructor:

City::~City()
{
    vector <Base*>::iterator deleteIterator;
    for (deleteIterator = m_basesVector.begin() ; deleteIterator != m_basesVector.end() ; deleteIterator++)
        m_basesVector.erase(deleteIterator);
}  

thanks.

回答1:

erase invalidates the iterator. You can't use it any more. Luckily for you, it returns an iterator that you can use:

vector <Base*>::iterator deleteIterator = m_basesVector.begin();
while (deleteIterator != m_basesVector.end()) {
    deleteIterator = m_basesVector.erase(deleteIterator);
}

Or:

m_basesVector.clear();

Are you responsible for freeing the memory referred to by the pointers in the vector? If that's the reason that you're iterating (and your real program has more code that you haven't shown, that frees those objects in the loop), then bear in mind that erasing from the beginning of a vector is a slow operation, because at each step, all the elements of the vector have to be shifted down one place. Better would be to loop over the vector freeing everything (then clear() the vector, although as Mike says that's not necessary if the vector is a member of an object that's being destroyed).



回答2:

The problem is that you are trying to use an iterator while using the erase() function. erase(), push_back(), insert(), and other modifying functions invalidate iterators in STL.

Just use the clear() function:

City::~City()
{
    m_basesVector.clear();
}  


回答3:

If you are trying to free the data in the vector, do this:

for (std::vector<Base*>::iterator it = v.begin(), e = b.end(); it != e; ++it) 
    delete *it;


回答4:

Posting this just incase anyone else has this this problem and attempts this solution wondering why it's not working here's an actual solution/explanation.

@Steve Jessop - Your code is flawed and you've also got it written here... ( I've also edited his post to fix the issue as soon as it's approved it'll be fixed in the original post )

http://techsoftcomputing.com/faq/3779252.html

I don't see how this is a "Solution" to the issue when it create an new issue by making an endless loop there should be a deleteIterator++ within the while loop so that it actually reaches the end of the vector.

Also I've ran into this problem and my solution was inside the while loop checking whether the iterator was equal to the end or if the vector size was 0 and breaking before attempting to incrementing the iterator.

Ex.

    std::vector<RankPlayer*>::iterator Rank_IT = CurrentPlayers.begin();

    while ( Rank_IT != CurrentPlayers.end() ) 
    {    
        RankPlayer* SelPlayer = (*Rank_IT);

        if( strstr( SelPlayer->GamerTag, this->GamerTag ) != NULL )
        {

            delete[] SelPlayer->PlayerData;
            delete[] SelPlayer;
            Rank_IT = CurrentPlayers.erase( Rank_IT );
        }

        if( Rank_IT == CurrentPlayers.end() || CurrentPlayers.size() == 0 )
        {
            break;
        }
            ++Rank_IT;
    }


回答5:

This is not relevant to the original problem posted above, but Google search on the error takes me to this page so I am posting it here for anyone to see.

I ran into this error message recently and all lines of codes checked out (there was no 'erase' or anything alike; the vector was merely read).

Eventually, I realized that there is a problem with nested loops.

For example, consider something like this:

`for (it=begin(); it!=end();i++)
{
    for (; it!=end();i++)
    {
    }
}`

When you are done with the nested loop, it will increment the iterator - and then, the parent loop will increment it again(!), ultimately making the iterator step over the end(). I.e. it would be "end()+1" if there were such a thing. Consequently, the parent loop throws this error at the next check.

To get around this, I ended up insert this line after the child loop:

`if (it == vStringList.end()) --it;`

Dirty, but works :D

I know it may be obvious to some, but I've been scratching my head over this for a while, lol



回答6:

Any iterator pointing to the deleted element or to the elements after the one that is deleted gets invalidated when the vector's erase method is called. Erase method returns a valid iterator pointing to the next element in the vector. You should use that iterator to continue your looping & not increment the invalidated iterator. You may also use the clear method to remove all the elements in the vector. However, you will need to remember to explicitly de-allocate any allocated memory for the elements.



回答7:

This code leaks all the contents of the vector - you have to delete *deleteIterator in the loop too. You can avoid all of this by using Base instead of Base* as the vector contents, then clear() will destruct them for you. Or use boost::ptr_vector which automates destruction if you do need raw pointers.

Calling erase() in a forward iteration like this can be very costly if the vector is large, as every element above the current position has to be moved down to ensure elements remain contiguous. Avoid manual erase of the type you propose, for this and other reasons.



回答8:

Vector iterators are incrementable, but if you delete elements, the vector contents are modified and thus the iterator is invalid.

So, if you delete objects, you should use the return value of erase() that gives you the next valid iterator.