Itérer un C++ Vecteur à l'aide d'un "pour" boucle

je suis 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 à travers un vecteur via des indices, le premier paramètre de la boucle for est toujours quelque chose 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?

98
demandé sur Peter Mortensen 2012-10-03 09:50:18

7 réponses

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

Pas de. Ce n'est pas une mauvaise pratique, mais cela rend votre code certain flexibilité .

habituellement, pré-C++11 le code pour itérer sur les éléments de conteneur utilise des 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 bibliothèque standard prennent en charge et fournissent des itérateurs et étant donné que si à un stade ultérieur de développement vous devez changer un autre conteneur, alors ce code n'a pas besoin d'être changé.

Note: le code D'écriture qui fonctionne avec tous les conteneurs de bibliothèque standard possibles n'est pas aussi facilement possible qu'il pourrait sembler l'être.

68
répondu Alok Save 2017-04-22 02:00:20

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, parce que j'ai vu beaucoup du code qui utilise votre manière mentionnée plutôt que le code de style iterator .

ce qui suit peut être des raisons de gens qui ne considèrent pas vector.size() façon de boucler:

  1. être paranoïaque en appelant 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() à la for boucle elle-même
  3. changement ultérieur du conteneur de std::vector à un autre (par exemple map , list ) exigera également le changement du mécanisme de boucle, parce que tous les conteneurs ne supportent pas size() style de boucle

C++11 fournit une bonne facilité pour se déplacer à travers les conteneurs. C'est ce qu'on appelle "plage basée pour boucle" (ou "améliorée pour la boucle" en Java).

avec peu de code, vous pouvez parcourir la totalité (obligatoire!) std::vector :

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;
74
répondu iammilind 2014-09-29 12:03:13

la manière la plus propre d'itérer à travers un vecteur est par l'intermédiaire d'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 auto par le type d'itérateur et utiliser les fonctions de membre au lieu des fonctions globales begin et end.

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 de vector . Si vous changez vector en une autre classe" collection-type", votre code fonctionnera probablement toujours. Vous pouvez, cependant, faire quelque chose de similaire à Java. Il n'y a pas beaucoup de différence conceptuelle; C++, cependant, utilise des gabarits pour implémenter ceci (par rapport aux génériques en Java); par conséquent, l'approche fonctionnera pour tous les types pour lesquels les fonctions begin et end sont définies, même pour les types non-classe tels que les tableaux statiques. Voir ici: comment le basé sur la gamme de travail pour les tableaux simples?

54
répondu JohnB 2017-05-23 12:02:45

La bonne façon de le 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 activity, il suffit d'écrire activity au lieu de T.

ce type de méthode fonctionne sur chaque STL (pas seulement les vecteurs, ce qui est un peu mieux).

si vous voulez toujours utiliser les index, la façon est:

for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}
28
répondu DiGMi 2012-10-03 06:08:26

il y a quelques bonnes raisons d'utiliser des itérateurs, dont certaines sont mentionnées ici:

changer de conteneur n'invalide pas votre code.

i.e., si vous passez d'un std::vector à un std::list, ou std::set, vous ne pouvez pas utiliser d'indices numériques pour obtenir votre valeur contenue. L'utilisation d'un itérateur est toujours valide.

capture D'exécution d'itération invalide

si vous modifiez votre au milieu de votre boucle, la prochaine fois que vous utilisez votre iterator il lancera une exception iterator invalide.

6
répondu Eddie Parker 2014-06-23 16:13:21

avec STL, les programmeurs utilisent iterators pour traverser les conteneurs, puisque iterator est un concept abstrait, mis en œuvre dans tous les conteneurs standard. Par exemple, std::list n'a pas du tout de operator [] .

4
répondu ForEveR 2017-04-22 02:01:43

j'ai été surpris personne n'a mentionné que itérer à travers un tableau avec un index entier rend facile pour vous d'écrire du code défectueux en souscrivant un tableau avec le mauvais index. Par exemple, si vous avez des boucles imbriquées en utilisant i et j comme indices, vous pourriez incorrectement subscrire un tableau avec j plutôt que i et ainsi introduire un défaut dans le programme.

En revanche, les autres formes énumérées ici, à savoir la gamme la boucle for , et les itérateurs, sont beaucoup moins sujets aux erreurs. La sémantique du langage et le mécanisme de vérification de type du compilateur vous empêcheront d'accéder accidentellement à un tableau en utilisant le mauvais index.

0
répondu Diomidis Spinellis 2018-04-19 20:51:21