Quelle est la bonne façon d'itérer sur un vecteur en C ++?
Considérez ces deux fragments de code, celui-ci fonctionne très bien:
for (unsigned i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
et celui-là:
for (int i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
qui génère warning: comparison between signed and unsigned integer expressions
.
Je suis nouveau dans le monde du C ++, donc la unsigned
variable me semble un peu effrayante et je sais que les unsigned
variables peuvent être dangereuses si elles ne sont pas utilisées correctement, alors - est-ce correct?
.size()
n'est pas de typeunsigned
akaunsigned int
. C'est de typestd::size_t
.std::size_t
est un typedef défini par _implementation. Voir la norme.std::size_t
peut être équivalent àunsigned
votre implémentation actuelle, mais ce n'est pas pertinent. Le faire semblant peut entraîner un code non portable et un comportement indéfini.std::size_t
en pratique. Pensez-vous que nous avons tout couvert encore dans ce flux de commentaires décousus sur 6 ans?Réponses:
Pour itérer en arrière, voir cette réponse .
L'itération vers l'avant est presque identique. Il suffit de changer les itérateurs / décrément de swap par incrément. Vous devriez préférer les itérateurs. Certaines personnes vous disent d'utiliser
std::size_t
le type de variable d'index. Cependant, ce n'est pas portable. Utilisez toujours lesize_type
typedef du conteneur (Bien que vous puissiez vous en sortir avec seulement une conversion dans le cas d'itération vers l'avant, il pourrait en fait se tromper complètement dans le cas d'itération vers l'arrière lors de l'utilisationstd::size_t
, au cas oùstd::size_t
est plus large que ce qui est le typedef desize_type
) :Utilisation de std :: vector
Utilisation d'itérateurs
L'important est de toujours utiliser le formulaire d'incrémentation de préfixe pour les itérateurs dont vous ne connaissez pas les définitions. Cela garantira que votre code est aussi générique que possible.
Utilisation de Range C ++ 11
Utiliser des indices
Utilisation de tableaux
Utilisation d'itérateurs
Utilisation de Range C ++ 11
Utiliser des indices
Lisez la réponse itérative à l'envers à quel problème l'
sizeof
approche peut céder, cependant.la source
for (auto p : polygon){sum += p;}
Quatre ans se sont écoulés, Google m'a donné cette réponse. Avec le standard C ++ 11 (alias C ++ 0x ), il existe en fait une nouvelle façon agréable de le faire (au prix de briser la compatibilité descendante): le nouveau
auto
mot-clé. Cela vous évite d'avoir à spécifier explicitement le type d'itérateur à utiliser (en répétant à nouveau le type de vecteur), quand il est évident (pour le compilateur), quel type utiliser. Env
étant votrevector
, vous pouvez faire quelque chose comme ceci:C ++ 11 va encore plus loin et vous donne une syntaxe spéciale pour itérer sur des collections comme des vecteurs. Il supprime la nécessité d'écrire des choses qui sont toujours les mêmes:
Pour le voir dans un programme de travail, créez un fichier
auto.cpp
:Au moment d'écrire ceci, lorsque vous le compilez avec g ++ , vous devez normalement le configurer pour qu'il fonctionne avec la nouvelle norme en donnant un indicateur supplémentaire:
Vous pouvez maintenant exécuter l'exemple:
Veuillez noter que les instructions sur la compilation et l'exécution sont spécifiques au compilateur gnu c ++ sous Linux , le programme doit être indépendant de la plateforme (et du compilateur).
la source
for (auto& val: vec)
std::vector<int> v = std::vector<int>();
, ou auriez-vous pu simplement l'utiliser à lastd::vector<int> v;
place?Dans le cas spécifique de votre exemple, j'utiliserais les algorithmes STL pour accomplir cela.
Pour un cas plus général, mais toujours assez simple, je choisirais:
la source
Concernant la réponse de Johannes Schaub:
Cela peut fonctionner avec certains compilateurs mais pas avec gcc. Le problème ici est la question de savoir si std :: vector :: iterator est un type, une variable (membre) ou une fonction (méthode). Nous obtenons l'erreur suivante avec gcc:
La solution utilise le mot-clé 'typename' comme indiqué:
la source
T
est un argument de modèle, et donc l'expressionstd::vector<T*>::iterator
est un nom dépendant. Pour qu'un nom dépendant soit analysé en tant que type, il doit être ajouté par letypename
mot - clé, comme l'indique le diagnostic.Un appel à
vector<T>::size()
renvoie une valeur de typestd::vector<T>::size_type
, not int, unsigned int ou autre.De manière générale, l'itération sur un conteneur en C ++ se fait à l'aide d' itérateurs , comme celui-ci.
Où T est le type de données que vous stockez dans le vecteur.
Ou en utilisant les différents algorithmes d'itération (
std::transform
,std::copy
,std::fill
,std::for_each
etc.).la source
Utilisation
size_t
:Citant Wikipédia :
la source
#include <cstddef>
plutôt que<stddef.h>
ou, pire, l'intégralité de[c]stdlib
et d'utiliserstd::size_t
plutôt que la version non qualifiée - et même pour toute autre situation où vous avez le choix entre<cheader>
et<header.h>
.Un peu d'histoire:
Pour représenter si un nombre est négatif ou non, utilisez un bit «signe».
int
est un type de données signé, ce qui signifie qu'il peut contenir des valeurs positives et négatives (environ -2 à 2 milliards).Unsigned
ne peut stocker que des nombres positifs (et comme cela ne gaspille pas un peu de métadonnées, il peut en stocker plus: 0 à environ 4 milliards).std::vector::size()
renvoie ununsigned
, car comment un vecteur peut-il avoir une longueur négative?L'avertissement vous indique que l'opérande droit de votre déclaration d'inégalité peut contenir plus de données que la gauche.
Essentiellement, si vous avez un vecteur avec plus de 2 milliards d'entrées et que vous utilisez un entier pour vous indexer, vous rencontrerez des problèmes de débordement (l'int se terminera par 2 milliards négatifs).
la source
J'utilise habituellement BOOST_FOREACH:
Il fonctionne sur les conteneurs STL, les tableaux, les chaînes de style C, etc.
la source
Pour être complète, la syntaxe C ++ 11 n'autorise qu'une seule autre version pour les itérateurs ( ref ):
Ce qui est également confortable pour une itération inverse
la source
En C ++ 11
J'utiliserais des algorithmes généraux comme
for_each
pour éviter de chercher le bon type d'itérateur et d'expression lambda pour éviter des fonctions / objets nommés supplémentaires.Le petit exemple "joli" pour votre cas particulier (en supposant que le polygone est un vecteur d'entiers):
testé sur: http://ideone.com/i6Ethd
N'oubliez pas d' inclure: algorithme et, bien sûr, vecteur :)
Microsoft a en fait également un bel exemple à ce sujet:
source: http://msdn.microsoft.com/en-us/library/dd293608.aspx
la source
la source
Le premier est de type correct et correct au sens strict. (Si vous y pensez, la taille ne peut jamais être inférieure à zéro.) Cependant, cet avertissement me semble être l'un des bons candidats pour être ignoré.
la source
i == INT_MAX
,i++
provoque alors un comportement indéfini. À ce stade, tout peut arriver.Déterminez si vous devez répéter
L'en
<algorithm>
-tête standard nous fournit des installations pour cela:D'autres fonctions de la bibliothèque d'algorithmes effectuent des tâches courantes - assurez-vous de savoir ce qui est disponible si vous voulez vous épargner des efforts.
la source
Détail obscur mais important: si vous dites "pour (auto it)" comme suit, vous obtenez une copie de l'objet, pas l'élément réel:
Pour modifier les éléments du vecteur, vous devez définir l'itérateur comme référence:
la source
Si votre compilateur le prend en charge, vous pouvez utiliser une plage basée sur pour accéder aux éléments vectoriels:
Impressions: 1 2 3. Notez que vous ne pouvez pas utiliser cette technique pour modifier les éléments du vecteur.
la source
Les deux segments de code fonctionnent de la même manière. Cependant, la route unsigned int "est correcte. L'utilisation de types unsigned int fonctionnera mieux avec le vecteur dans l'instance que vous l'avez utilisée. L'appel de la fonction membre size () sur un vecteur renvoie une valeur entière non signée, vous voulez donc comparer la variable "i" à une valeur de son propre type.
De plus, si vous êtes encore un peu inquiet de l'apparence de "unsigned int" dans votre code, essayez "uint". Il s'agit essentiellement d'une version abrégée de "unsigned int" et cela fonctionne exactement de la même manière. Vous n'avez pas non plus besoin d'inclure d'autres en-têtes pour l'utiliser.
la source
Ajoutant cela car je ne l'ai pas trouvé mentionné dans aucune réponse: pour l'itération basée sur un index, nous pouvons utiliser
decltype(vec_name.size())
ce qui évalueraitstd::vector<T>::size_type
Exemple
la source