tags:

views:

2029

answers:

3

I'm trying to do a simple erase and keep getting errors.

Here is the snippet of code for my erase:

std::list<Mine*>::iterator iterMines = mines.begin();
for(int i = oldSizeOfMines; i >0 ; i--, iterMines++)
{
 if(player->distanceFrom(*iterMines) < radiusOfOnScreen)
 {
  onScreen.push_back(*iterMines);
  iterMines = onScreen.erase(iterMines);
  iterMines--;
 }
}

I keep getting a compiler message:

1>c:\users\owner\desktop\bosconian\code\bosconian\environment.cpp(158) : error C2664: 'std::list<_Ty>::_Iterator<_Secure_validation> std::list<_Ty>::erase(std::list<_Ty>::_Iterator<_Secure_validation>)' : cannot convert parameter 1 from 'std::list<_Ty>::_Iterator<_Secure_validation>' to 'std::list<_Ty>::_Iterator<_Secure_validation>'
1>        with
1>        [
1>            _Ty=SpaceObject *,
1>            _Secure_validation=true
1>        ]
1>        and
1>        [
1>            _Ty=Mine *,
1>            _Secure_validation=true
1>        ]
1>        and
1>        [
1>            _Ty=SpaceObject *,
1>            _Secure_validation=true
1>        ]
1>        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

I'm puzzled because I believe I'm giving it the correct iterator.

Mine is a subclass of SpaceObject (a second generation subclass that is)

Does this have anything to do with it? And how would I fix it?

+4  A: 

The problem is you are trying to use the iterator of mines as an iterator in the onScreen list. This will not work.

Did you mean to call mines.erase(iterMines) instead of onScreen.erase(iterMines)?

grepsedawk
I feel dumb. Thanks a lot though.
Chad
+2  A: 
std::list<Mine*>::iterator iterMines = mines.begin();
for(int i = oldSizeOfMines; i >0 ; i--, iterMines++)
{
        if(player->distanceFrom(*iterMines) < radiusOfOnScreen)
        {
                onScreen.push_back(*iterMines);
                iterMines = onScreen.erase(iterMines);
                iterMines--;
        }
}

One real problem, and one possible solution:

erase will give you the next iterator after the removed element. So if you are at the beginning, and erase, you will be given the new beginning. If you then decrement the iterator, you decrement before the begin. And this is invalid. Better factor out the iterMines++ into the body of the loop:

std::list<Mine*>::iterator iterMines = mines.begin();
for(int i = oldSizeOfMines; i >0 ; i--)
{
        if(player->distanceFrom(*iterMines) < radiusOfOnScreen)
        {
                onScreen.push_back(*iterMines);
                iterMines = mines.erase(iterMines); // change to mines!!
        } else { 
            ++iterMines; // better to use ++it instead of it++
        }
}

Better use pre-increment for that since you never know what an iterator does behind the scene when it creates a copy of itself. ++it will return the new iterator, while it++ will return a copy of the iterator before the increment. I have commented the part where the possible solution is too :)

Johannes Schaub - litb
erase not being uniform across collections is one of my main gripes with stl containers. Which is why I prefer using erase(iter++) idiom
grepsedawk
grepsedawk that quite dangerous for vector and deque, which will generally invalidate all iterators when you erase an element from the middle of the container (for vector only the following ones, but that's what you use there). thus it's always better to use the return value of erase instead.
Johannes Schaub - litb
Agreed, but for [multi]map/set it is the only choice. You can also use the reverse iterator technique to achieve safe results with vector
grepsedawk
A: 

more simple method List.erase(p)的用法