Quand dois-je utiliser std::size_t?
Je me demande dois-je utiliser std::size_t
pour des boucles et des trucs au lieu de int
?
Par exemple:
#include <cstdint>
int main()
{
for (std::size_t i = 0; i < 10; ++i) {
//std::size_t OK here? Or should I use, say, unsigned int instead?
}
}
En général, quelles sont les bonnes pratiques quant à l'utilisation std::size_t
?
Vous devez vous connecter pour publier un commentaire.
Une bonne règle de base est pour tout ce que vous avez besoin de comparer à la condition de la boucle contre quelque chose qui est naturellement un
std::size_t
lui-même.std::size_t
est le type de toutsizeof
expression et comme c'est la garantie d'être en mesure d'exprimer la taille maximale d'un objet (y compris toute matrice) en C++. Par extension, il est aussi la garantie d'être assez grand pour n'importe quel tableau de l'index de sorte qu'il est naturel pour un type de boucle par index sur un tableau.Si vous êtes juste en comptant jusqu'à un numéro, puis il peut être plus naturel d'utiliser le type de la variable qui contient le nombre ou une
int
ouunsigned int
(si assez grand) comme cela devrait être naturel de la taille de la machine.size_t
quand vous devriez peut conduire à les failles de sécurité.size_t
est le type de résultat de lasizeof
opérateur.Utilisation
size_t
pour les variables de la taille du modèle ou de l'index dans un tableau.size_t
transmet sémantique: vous savez immédiatement qu'il représente une taille en octets ou d'un indice, plutôt que juste un autre nombre entier.Également, à l'aide de
size_t
pour représenter une taille en octets permet de faire du code portable.La
size_t
type est destiné à spécifier le taille de quelque chose, de sorte qu'il est naturel de les utiliser, par exemple, obtenir la longueur d'une chaîne, puis le traitement de chaque personnage:Vous ne de regarder dehors pour des conditions aux limites bien sûr, puisque c'est un type non signé. La limite à l'extrémité supérieure est généralement pas important puisque le maximum est généralement de grande taille (bien qu'il est possible pour y arriver). La plupart des gens il suffit d'utiliser une
int
pour ce genre de chose, parce qu'ils ont rarement des structures ou des tableaux qui obtiennent assez grande pour dépasser la capacité deint
.Mais attention à des choses comme:
qui va provoquer une boucle infinie en raison de l'emballage du comportement des valeurs non signées (bien que j'ai vu les compilateurs en garde contre cette). Cela peut aussi être atténué par l' (un peu plus difficile à comprendre, mais au moins immunitaire à l'enrobage des problèmes):
Par le passage de la décrémenter post-vérifier les effets secondaires de la poursuite de son état, ce n'est la vérification de la poursuite sur la valeur avant de décrémentation, mais utilise toujours la valeur décrémentée à l'intérieur de la boucle (c'est pourquoi la boucle s'exécute de
len .. 1
plutôt quelen-1 .. 0
).strlen
à chaque itération d'une boucle. 🙂 Vous pouvez faire quelque chose comme ceci:for (size_t i = 0, len = strlen(str); i < len; i++) ...
for (size_t i = strlen (str); i --> 0;)
-->
"va" de l'opérateur (voir stackoverflow.com/questions/1642028/...). Ont intégré votre suggestion dans la réponse.if (i == 0) break;
à la fin de la boucle for (p. ex.,for (size_t i = strlen(str) - 1; ; --i)
. (J'aime vôtre mieux, mais je me demandais si cela ne fonctionne tout aussi bien).Par définition,
size_t
est le résultat de lasizeof
de l'opérateur.size_t
a été créé pour désigner les tailles.Le nombre de fois que vous faites quelque chose (10, dans votre exemple) n'est pas sur les tailles, alors pourquoi utiliser
size_t
?int
, ouunsigned int
, devrait être ok.Bien sûr, il est pertinent de ce que vous faites avec
i
l'intérieur de la boucle. Si vous passez à une fonction qui prend ununsigned int
, par exemple, choisirunsigned int
.En tout cas, je vous recommande d'éviter les conversions de type implicites. Faire toutes les conversions de type explicite.
size_t
est très lisible moyen de spécifier la dimension de la taille d'un élément de longueur d'une chaîne, la quantité d'octets qu'un pointeur prend, etc.Il est également portable à travers les plates - formes, vous trouverez que la 64 bits et 32 bits à la fois se comporter correctement avec les fonctions du système et
size_t
- quelque chose quiunsigned int
ne pourrait pas faire (par exemple, quand devez-vous utiliserunsigned long
Utiliser std::size_t pour l'indexation de dénombrement et de style C tableaux.
Pour les conteneurs STL, vous aurez (par exemple)
vector<int>::size_type
, qui devrait être utilisé pour l'indexation et le comptage des éléments vectoriels.Dans la pratique, ils sont généralement de deux entiers non signés, mais il n'est pas garanti, en particulier lors de l'utilisation de la coutume allocateurs.
std::size_t
est généralementunsigned long
(8 octets, 64 bits des systèmes d') plutôt que deunisgned int
(4 octets).size_t
, mais, depuis l'index peut être négatif. On pourrait utilisersize_t
pour sa propre instance d'un tel tableau, si l'on ne veut pas aller négative, si.+
sur les pointeurs, il semblerait queptrdiff_t
est celle à utiliser pour les indices.vector<T>::size_type
(et idem pour tous les autres contenants), c'est plutôt inutile, car il est effectivement garanti àsize_t
- il de la définition de type d'Allocator::size_type
, et pour les restrictions en ce qui concerne les contenants voir 20.1.5/4 - en particulier,size_type
doit êtresize_t
, etdifference_type
doit êtreptrdiff_t
. Bien sûr, la valeur par défautstd::allocator<T>
satisfait à ces exigences. Utilisez donc la plus courtesize_t
et ne vous embêtez pas avec le reste du lot 🙂Bientôt la plupart des ordinateurs seront les architectures 64 bits avec 64-bit OS:es les programmes en cours d'exploitation sur les contenants de milliards d'éléments. Ensuite, vous doit utilisation
size_t
au lieu deint
comme indice de boucle, sinon, votre indice de enrouler autour de à la 2^32:élément th, sur les versions 32 et 64 bits des systèmes.Préparer l'avenir!
long int
plutôt qu'unint
. Sisize_t
est pertinente sur un OS 64 bits, il était tout aussi pertinent sur un 32-bit OS.réponse courte:
presque jamais
réponse longue:
Toutes les fois que vous besoin d'avoir un vecteur de char plus grand que 2 go sur un système 32 bits. Dans tous les autres cas d'utilisation, à l'aide d'un type signé est beaucoup plus sûr que d'utiliser un type non signé.
exemple:
La signature de l'équivalent de
size_t
estptrdiff_t
, pasint
. Mais à l'aide deint
est encore beaucoup mieux dans la plupart des cas que size_t.ptrdiff_t
estlong
sur 32 bits et 64 bits des systèmes d'.Cela signifie que vous avez toujours pour convertir size_t chaque fois que vous interagissez avec un std::conteneurs, qui n'est pas très beau. Mais sur une native de la conférence, les auteurs de c++ mentionné que la conception de std::vector avec un unsigned size_t était une erreur.
Si votre compilateur vous donne des avertissements sur les conversions implicites de ptrdiff_t à size_t, vous pouvez vous rendre explicite avec le constructeur de la syntaxe:
si voulez juste pour itérer sur une collection, sans limites cheque, utilisez la gamme de base pour:
ici quelques mots de Bjarne Stroustrup (C++ auteur) à natifs
Pour certaines personnes, cette signed/unsigned erreur de conception dans le TSL est une raison suffisante, à ne pas utiliser les std::vector, mais plutôt une mise en œuvre.
for(int i = 0; i < get_size_of_stuff(); i++)
. Maintenant, c'est sûr, vous ne voulez pas vous faire beaucoup de cru de boucles, mais - allez, vous les utilisez trop.x + 1 < y
équivalent àx < y - 1
, mais ils ne sont pas avec unsigend entiers. Qui peut facilement introduire des bugs quand les choses sont transformés qui sont supposés être équivalent.Lors de l'utilisation de size_t être prudent avec l'expression suivante
Vous obtiendrez la valeur false dans le cas de l'expression, indépendamment de ce que la valeur de x.
Il m'a fallu plusieurs jours pour réaliser cela (le code est tellement simple que je n'ai pas fait de test de l'unité), bien qu'il ne prend que quelques minutes pour comprendre la source du problème. Pas sûr que c'est mieux de faire un moulage ou de l'utilisation de zéro.
Deux façons devrait fonctionner. Voici mon essai
La sortie: i-7=18446744073709551614 (int)(i-7)=-2
Je voudrais d'autres commentaires.
(int)(i - 7)
est un dépassement de capacité qui est jeté à l'int
par la suite, tandis queint(i) - 7
n'est pas un dépassement de capacité depuis la première convertiri
à unint
, puis soustraire7
. En outre, j'ai trouvé votre exemple de la confusion.size_t est retourné par les différentes bibliothèques pour indiquer que la taille du conteneur est non nul. Vous l'utilisez lorsque vous obtenez une fois de retour :0
Cependant, dans l'exemple ci-dessus en boucle sur un size_t est un bug potentiel. Considérez les points suivants:
l'utilisation des entiers non signés a le potentiel de créer ces types de questions subtiles. Donc à mon humble avis, je préfère utiliser size_t seulement quand j'ai interagir avec les conteneurs/types qui en ont besoin.
size_t
est un type non signé qui peut contenir la valeur entière maximale pour votre architecture, de sorte qu'il est protégé contre les débordements d'entiers en raison de signer (signé int0x7FFFFFFF
incrémenté de 1 vous donne -1) ou de taille courte (unsigned short int 0xFFFF incrémenté de 1 vous donne 0).Il est principalement utilisé dans le tableau d'indexation/boucles/de l'adresse de l'arithmétique et ainsi de suite. Des fonctions comme
memset()
et autres, acceptersize_t
seulement, parce que, théoriquement, vous pourriez avoir un bloc de mémoire de taille2^32-1
(sur 32 bits plate-forme).Pour la simple boucle n'est pas la peine et utiliser seulement int.
size_t est un type unsigned type intégral, qui peut représenter le plus grand entier sur votre système.
À n'utiliser que si vous avez besoin de très grands tableaux,matrices, etc.
Certaines fonctions renvoient un size_t et votre compilateur vous avertira si vous essayez de faire des comparaisons.
Éviter que, par l'utilisation d'un approprié signed/unsigned type de données ou tout simplement enfermé pour un rapide hack.
size_t est unsigned int. donc, chaque fois que vous voulez unsigned int vous pouvez l'utiliser.
Je l'utilise quand je veux spécifier la taille du tableau , compteur ect...