La plupart du temps, nous utilisons le type entier pour représenter les variables d'index. Mais dans certaines situations, nous sommes obligés de choisir
std::vector<int> vec;
....
for(int i = 0; i < vec.size(); ++i)
....
Cela entraînera le compilateur à déclencher l'avertissement que l'utilisation mixte de variables signées / non signées. si je crée la variable d'index en tant que for( size_t i = 0; i < vec.size(); i++ )
(ou an unsigned int
), cela résoudra les problèmes.
Lorsqu'il est plus spécifique d'utiliser des types de fenêtres, la plupart des API Windows traitent avec DWORD (qui est typé comme non signé depuis longtemps).
Donc, lorsque j'utilise une itération similaire, cela provoquera à nouveau le même avertissement. Maintenant, si je le réécris comme
DWORD dwCount;
....
for(DWORD i = 0; i < dwCount; ++i)
....
Je trouve ça un peu bizarre. Ce pourrait être le problème avec les perceptions.
Je suis d'accord que nous sommes censés utiliser le même type de variable d'index pour éviter que les problèmes de plage ne se produisent avec les variables d'index. Par exemple, si nous utilisons
_int64 i64Count; //
....
for(_int64 i = 0; i < i64Count; ++i)
....
Mais dans le cas de DWORD, ou d'entiers non signés, y a-t-il des problèmes à le réécrire comme
for(int i = 0; (size_t)i < vec.size(); ++i)
Comment la plupart des gens travaillent avec des problèmes similaires?
std::size_t
c'est un rang plus élevé que int (ou même long). Si jamais la taille du vecteur dépassestd::numeric_limits<int>::max()
, vous regretterez d'avoir utilisé int.Réponses:
vector a un typedef qui vous indique le type correct à utiliser: -
Il est presque toujours défini comme étant size_t mais vous ne pouvez pas vous y fier
la source
auto i = 0
? Cela n'aide pas du tout,i
devenir unint
.using index_t = std::vector<int>::size_type;
.Utilisez un itérateur pour cela, pas une
for
boucle.Pour les autres, tant que le type de variable est de la même taille,
static_cast
devrait fonctionner très bien (c'est-DWORD
à- dire pourint16_t
)la source
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i)
est une douleur à écrire. Avoirfor (auto i = vec.begin();...
est beaucoup plus lisible. Bien sûr,foreach
est également en C ++ 11.Le cas que vous avez décrit est également une des choses que je n'aime pas en C ++. Mais j'ai appris à vivre avec ça, soit en utilisant
for( size_t i = 0; i < vec.size(); i++ )
ou
for( int i = 0; i < (int)vec.size(); i++ )
(bien sûr, ce dernier uniquement lorsqu'il n'y a aucun risque de débordement int).
la source
La raison pour laquelle il vous avertit de la comparaison entre signé et non signé est que la valeur signée sera probablement convertie en non signé, ce qui pourrait ne pas être ce que vous attendez.
Dans votre exemple (comparé
int
àsize_t
),int
sera implicitement converti ensize_t
(à moinsint
que sa portée ne soit en quelque sorte supérieuresize_t
). Ainsi, si leint
est négatif, il sera probablement supérieur à la valeur à laquelle vous le comparez en raison de l'habillage. Ce ne sera pas un problème si votre index n'est jamais négatif, mais vous obtiendrez toujours cet avertissement.Au lieu de cela, utilisez un type non signé ( par exemple
unsigned int
,size_t
ou, comme John B recommande ,std::vector<int>::size_type
) pour votre variable d'index:Soyez prudent lors du décompte, cependant:
Ce qui précède ne fonctionnera pas car il
i >= 0
est toujours vrai lorsqu'ili
n'est pas signé. Utilisez plutôt "l' opérateur flèche " pour les boucles qui décomptent:Comme d'autres réponses le soulignent, vous devez normalement utiliser un itérateur pour parcourir a
vector
. Voici la syntaxe C ++ 11:la source
unsigned int
ne soit pas assez grand pour contenir la taille.Une nouvelle option pour C ++ 11, vous pouvez faire des choses comme suit
for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}
et
for(decltype(dWord) i = 0; i < dWord; ++i) {...}
Bien qu'il répète un peu plus que la boucle for de base, il n'est pas aussi long que les façons de spécifier les valeurs d'avant '11, et l'utilisation de ce modèle fonctionnera de manière cohérente pour la plupart, sinon la totalité, des termes possibles que vous auriez veulent comparer, ce qui le rend idéal pour la refactorisation de code. Cela fonctionne même pour des cas simples comme celui-ci:
int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)
De plus, bien que vous deviez utiliser
auto
chaque fois que vous définissezi
une valeur intelligente (commevec.begin()
), celadecltype
fonctionne lorsque vous définissez une constante comme zéro, où auto résoudrait simplement celaint
car 0 est un simple littéral entier.Pour être honnête, j'aimerais voir un mécanisme de compilation pour étendre la
auto
détermination de type pour les incrémenteurs de boucle afin de regarder la valeur à comparer.la source
J'utilise un cast en int, comme dans
for (int i = 0; i < (int)v.size(); ++i)
. Oui, c'est moche. Je le blâme sur la conception stupide de la bibliothèque standard où ils ont décidé d'utiliser des entiers non signés pour représenter les tailles. (Pour ... quoi? Étendre la plage d'un bit?)la source
if(v.size()-1 > 0) { ... }
retourner vrai pour un conteneur vide? Le problème est que les tailles sont également souvent utilisées en arithmétique, en particulier. avec des conteneurs basés sur l'index, ce qui pose problème étant donné qu'ils ne sont pas signés. Fondamentalement, l'utilisation de types non signés pour autre chose que 1) des manipulations au niveau du bit ou 2) l'arithmétique modulaire appelle des ennuis.if(v.size() > 1) { ... }
car cela rend l'intention plus claire, et comme bonus supplémentaire la question du signé / non signé devient nulle), je vois comment dans certains cas spécifiques la signature pourrait être utile. Je me suis trompé.