2008-12-17 8 views
0

J'essaie de faire un simple effacement et continue d'obtenir des erreurs.Aide avec la fonction d'effacement de liste C++

Voici l'extrait de code pour mon effacement:

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--; 
    } 
} 

Je reçois un message du compilateur:

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 

Je suis perplexe parce que je crois que je lui donne le bon iterator .

mine est une sous-classe de SpaceObject (une deuxième sous-classe de génération qui est)

Est-ce que cela a quelque chose à voir avec elle? Et comment pourrais-je le réparer?

+0

Juste pour vous assurer, est la ligne 158 "iterMines = onScreen.erase (iterMines);"? –

Répondre

4

Le problème est que vous essayez d'utiliser l'itérateur des mines comme un itérateur dans la liste onScreen. Cela ne marchera pas. Vouliez-vous appeler mines.erase (iterMines) au lieu de onScreen.erase (iterMines)?

+0

Je me sens bête. Merci beaucoup. – Chad

2
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--; 
     } 
} 

Un vrai problème et une solution possible:

erase vous donnera la prochaine iterator après l'élément enlevé. Donc, si vous êtes au début, et effacez, vous recevrez le nouveau départ. Si vous décrémentez alors l'itérateur, vous décrémentez avant le début. Et ceci est invalide. Mieux facteur le iterMines++ dans le corps de la boucle:

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++ 
     } 
} 

Une meilleure utilisation pré-incrément pour que, puisque vous ne savez jamais ce que fait un itérateur derrière la scène quand il crée une copie de lui-même. ++it renverra le nouvel itérateur, tandis que it++ retournera une copie de l'itérateur avant l'incrément. Je l'ai commenté la partie où la solution est trop :)

+0

erase n'étant pas uniforme à travers les collections est l'un de mes principaux reproches avec des conteneurs stl. C'est pourquoi je préfère utiliser erase (iter ++) idiome – grepsedawk

+0

grepsedawk assez dangereux pour vector et deque, ce qui invalidera généralement tous les itérateurs lorsque vous effacerez un élément du milieu du conteneur (pour vector seulement les suivants, mais c'est ce que vous utiliser là). il est donc toujours préférable d'utiliser la valeur de retour d'effacement à la place. –

+0

D'accord, mais pour [multi] map/set c'est le seul choix. Vous pouvez également utiliser la technique de l'itérateur inverse pour obtenir des résultats sûrs avec le vecteur – grepsedawk