2010-11-04 8 views
5

j'ai vu le code suivant utilisé pour supprimer un élément choisi parmi std::vector:Est-ce que l'itérateur supporte + l'opérateur?

vector<hgCoord>::iterator it; 
int iIndex = 0; 
    const int iSelected = 5; 
for(it = vecPoints.begin(); it != vecPoints.end(); ++it, ++iIndex) 
{ 
    if(iIndex == iSelected) 
    { 
     vecPoints.erase(it); 
     break; 
    } 
} 

Je soutiens que ce code n'est pas efficace et doit être écrit comme suit:

vector<hgCoord>::iterator it; 
int iIndex = 0; 
    const int iSelected = 5; // we assume the vector has more than 5 elements. 

    vecPoints.erase(vecPoints.begin() + iSelected); 

Cependant, je ne suis pas Assurez-vous que ce code suit ou non la norme C++ STL.

+0

Vous avez raison, puisque 'std :: vector :: iterator' est un' RandomAccessIterator' (a.k.a. 'T *'). Rappelez-vous simplement que si vous avez moins de 5 éléments dans votre vecteur, votre deuxième algorithme échouera. –

+1

Si ces préfixes-'i' sont une forme de notation hongroise, je m'objecte fortement à l'un ou l'autre morceau de code. –

+0

@ eq-: quoi, parce que 'i' devrait être utilisé comme un préfixe signifiant' itérateur', vous voulez dire ;-p –

Répondre

12

Pour rendre ce code générique, donc il fonctionne, peu importe si l'itérateur soutient operator +, et utilise la mise en œuvre la plus efficace disponible:

template <typename C> 
void erase_at(C& container, typename C::size_type index) { 
    typename C::iterator i = container.begin(); 
    std::advance(i, index); 
    container.erase(i); 
} 

En interne, std::advance utilise operator + si le type iterator supporte. Autrement (par exemple pour std::list<>::iterator), il avance l'itérateur une étape à la fois dans une boucle, tout comme le premier code que vous avez publié.

+0

......... yup ..... +1 –

+3

En réponse à un commentaire sur la réponse supprimée de dirbeas - Je pense que la raison pour laquelle 'std :: advance' modifie son argument est quelque chose à voir avec le fait parce que c'est très agnostique, en particulier cela fonctionne sur tous les InputIterators, qui sont * bon marché * mais * dangereux * à copier. Lorsqu'il est utilisé avec un itérateur qui peut être uniquement un InputIterator, et non un ForwardIterator, vous ne pouvez plus utiliser l'ancienne valeur de manière sûre, donc même s'il renvoyait un itérateur, vous ne l'utiliseriez toujours que comme i = std :: avancez (i, n); », ou sur un code temporaire comme dans dribeas. Renvoyer 'vide 'aide à prévenir la stupidité. Parfois. Peut être. –

+0

Merci pour cette explication. – q0987

10

Les itérateurs à accès aléatoire prennent en charge l'addition et la soustraction, et les std::vector itérateurs sont à accès aléatoire.

2

vous soutenez correctement :)

1

Cela devrait fonctionner très bien pour un vecteur, car vecteur itérateurs sont itérateurs d'accès aléatoires, il est donc OK pour ajouter un décalage que vous avez fait. La même chose ne fonctionnera pas pour d'autres types de conteneurs (tels que deque ou map). Par conséquent, votre code est meilleur pour un vecteur, mais l'autre code peut avoir été conçu pour fonctionner avec d'autres types de conteneurs.

+0

En fait, 'deque' utilise aussi des itérateurs à accès aléatoire. –

+0

Je pense que le code modifié fonctionne pour vector, string et deque. – q0987

+0

@Fred Larson: Oups! Je ne sais pas pourquoi j'ai tapé deque, je voulais dire la liste! Merci pour la correction. – dajames