267 votes

C ++ itérer via vecteur à l'aide de la boucle for

Je suis donc nouveau dans le langage C ++. J'ai commencé à utiliser des vecteurs et j'ai remarqué que dans tout le code que je vois itérer sur un vecteur via des index, le premier paramètre de la boucle for est toujours basé sur le vecteur. En Java, je pourrais faire quelque chose comme ceci avec un ArrayList:

 for(int i=0; i < vector.size(); i++){
   vector[i].doSomething();
}
 

Y a-t-il une raison pour laquelle je ne vois pas cela en C ++? Est-ce une mauvaise pratique?

212voto

iammilind Points 29275

La raison pour laquelle vous ne voyez pas une telle pratique est tout à fait subjective et ne peut pas avoir une réponse définitive, car j'ai vu beaucoup de code qui utilise votre mentionné façon plutôt que d' iterator code de style.

La suite peut-être des raisons de personnes n'envisageant pas de vector.size() moyen de la boucle:

  1. Être paranoïaque à propos de l'appel de size() à chaque fois dans la boucle condition. Mais soit c'est un non-problème ou il peut être trivialement fixe
  2. Préférant std::for_each() sur le for boucle elle-même
  3. De changer plus tard le conteneur à partir d' std::vector pour les autres (par ex. map, list) sera également demander la modification de la boucle mécanisme, parce que pas chaque prise en charge du conteneur size() style de boucle

C++11, une bonne facilité de se déplacer à travers les conteneurs. Qui est appelé "la gamme en fonction de boucle" (ou "amélioré pour la boucle" en Java).

Avec le peu de code que vous pouvez parcourir à travers les complet (obligatoire!) std::vector:

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;

157voto

JohnB Points 5090

La façon la plus propre de l'itération par l'intermédiaire d'un vecteur est par les itérateurs:

for (auto it = begin (vector); it != end (vector); ++it) {
    it->doSomething ();
}

ou (équivalent à la ci-dessus)

for (auto & element : vector) {
    element.doSomething ();
}

Avant C++0x, vous devez remplacer l'auto par l'itérateur de type et de l'utilisation des fonctions de membre au lieu de fonctions globales de début et de fin.

C'est probablement ce que vous avez vu. Par rapport à l'approche que vous mentionnez, l'avantage est que vous n'avez pas dépendent fortement du type d' vector. Si vous modifiez vector à un autre de la collection "type" de la classe, votre code sera probablement encore du travail. Vous pouvez, cependant, faire quelque chose de similaire en Java ainsi. Il n'y a pas beaucoup de différence sur le plan conceptuel; C++, cependant, utilise des modèles pour mettre en œuvre la présente (par rapport à des génériques en Java); par conséquent, l'approche de travail pour tous les types pour qui begin et end fonctions sont définies, même pour les non-classe de types, tels que les tableaux statiques. Voir ici: Comment est la plage base de travail pour la plaine des tableaux?

135voto

Alok Save Points 115848

Est-il une raison je ne la vois pas en C++? Est-ce une mauvaise pratique?

Pas de. Il n'est pas une mauvaise pratique, mais il rend votre code certaine flexibilité.

Généralement, Avant C++11 le code pour itérer sur les éléments conteneurs utilise les Itérateurs, quelque chose comme:

std::vector<int>::iterator it = vector.begin();

C'est parce qu'il rend le code plus souple.
Tous les conteneurs de la bibliothèque standard de soutien et de fournir des itérateurs et compte tenu que si, à un stade ultérieur de développement, vous avez besoin de passer dans un autre récipient puis ce code n'a pas besoin d'être changé.

Remarque: l'Écriture de code qui fonctionne avec tous les possibles de la bibliothèque Standard du conteneur n'est pas aussi facile que cela puisse apparemment semblent être.

49voto

DiGMi Points 1404

La bonne façon de faire est:

 for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    it->doSomething();
 }
 

Où T est le type de la classe à l'intérieur du vecteur. Par exemple, si la classe était CActivity, écrivez simplement CActivity au lieu de T.

Ce type de méthode fonctionnera sur toutes les LIST (pas seulement les vecteurs, ce qui est un peu meilleur).

Si vous souhaitez toujours utiliser des index, la procédure est la suivante:

 for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}
 

8voto

Eddie Parker Points 2522

Il ya un couple de bonnes raisons pour utiliser des itérateurs, dont certains sont mentionnés ici:

Commutation des contenants plus tard ne pas invalider votre code.

c'est à dire, si vous allez à partir d'un std::vector pour un std::list, ou std::set, vous ne pouvez pas utiliser des indices numériques pour accéder à votre contenu de valeur. À l'aide d'un itérateur est toujours valide.

Exécution de capture de l'invalidité de l'itération

Si vous modifiez votre récipient dans le milieu de la boucle, la prochaine fois que vous utilisez votre itérateur qu'il va jeter un invalide itérateur exception.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X