Eu só estou querendo saber se devo usar std::size_t
para loops e outras coisas em vez de int
? Por exemplo:
#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?
}
}
Em geral, qual é a melhor prática em relação a quando usar std::size_t
?
size_t
quando necessário pode levar a erros de segurança .ssize_t
há valores assinados.size_t
é o tipo de resultado dosizeof
operador.Use
size_t
para variáveis que modelam tamanho ou índice em uma matriz.size_t
transmite semântica: você imediatamente sabe que representa um tamanho em bytes ou um índice, em vez de apenas outro número inteiro.Além disso, usar
size_t
para representar um tamanho em bytes ajuda a tornar o código portátil.fonte
O
size_t
tipo deve especificar o tamanho de algo, por isso é natural usá-lo, por exemplo, obtendo o comprimento de uma sequência e processando cada caractere:Você faz tem que tomar cuidado para condições de contorno, é claro, já que é um tipo não assinado. O limite na extremidade superior geralmente não é tão importante, pois o máximo geralmente é grande (embora seja possível chegar lá). A maioria das pessoas apenas usa um
int
para esse tipo de coisa porque raramente possui estruturas ou matrizes que são grandes o suficiente para exceder a capacidade dissoint
.Mas cuidado com coisas como:
o que causará um loop infinito devido ao comportamento de quebra de valores não assinados (embora eu tenha visto compiladores alertarem contra isso). Isso também pode ser aliviado pelo (um pouco mais difícil de entender, mas pelo menos imune a problemas de empacotamento):
Ao mudar o decremento para um efeito colateral pós-verificação da condição de continuação, ele faz a verificação da continuação do valor antes do decremento, mas ainda usa o valor decrementado dentro do loop (e é por isso que o loop é executado em
len .. 1
vez delen-1 .. 0
).fonte
strlen
cada iteração de um loop. :) Você pode fazer algo como isto:for (size_t i = 0, len = strlen(str); i < len; i++) ...
for (size_t i = strlen (str); i --> 0;)
-->
operador "vai para" (consulte stackoverflow.com/questions/1642028/… ). Incorporou sua sugestão na resposta.if (i == 0) break;
, no final do loop for (por exemplo,for (size_t i = strlen(str) - 1; ; --i)
(I como o seu melhor embora, mas apenas querendo saber se isso iria funcionar tão bem)..Por definição,
size_t
é o resultado dosizeof
operador.size_t
foi criado para se referir a tamanhos.O número de vezes que você faz alguma coisa (10, no seu exemplo) não é sobre tamanhos, então por que usar
size_t
?int
ouunsigned int
deve estar ok.Claro que também é relevante o que você faz com o
i
interior do loop. Se você o passar para uma função que faça umunsigned int
, por exemplo, escolhaunsigned int
.De qualquer forma, recomendo evitar conversões implícitas de tipo. Torne explícitas todas as conversões de tipo.
fonte
size_t
é uma maneira muito legível de especificar a dimensão de tamanho de um item - comprimento de uma string, quantidade de bytes que um ponteiro leva etc. Também é portátil em várias plataformas - você verá que 64 bits e 32 bits se comportam bem com as funções do sistema esize_t
- algo queunsigned int
pode não funcionar (por exemplo, quando você deve usarunsigned long
fonte
resposta curta:
quase nunca
resposta longa:
Sempre que você precisar de um vetor de char maior que 2gb em um sistema de 32 bits. Em todos os outros casos de uso, usar um tipo assinado é muito mais seguro do que usar um tipo não assinado.
exemplo:
O equivalente assinado de
size_t
éptrdiff_t
, nãoint
. Mas o usoint
ainda é muito melhor na maioria dos casos do que size_t.ptrdiff_t
élong
em sistemas de 32 e 64 bits.Isso significa que você sempre precisa converter de e para size_t sempre que interagir com um std :: containers, o que não é muito bonito. Mas em uma conferência nativa em andamento, os autores do c ++ mencionaram que projetar std :: vector com um size_t não assinado foi um erro.
Se o seu compilador fornecer avisos sobre conversões implícitas de ptrdiff_t para size_t, você poderá explicitá-lo com a sintaxe do construtor:
se quiser apenas iterar uma coleção, sem limites, use o intervalo com base em:
aqui algumas palavras de Bjarne Stroustrup (autor C ++) em nativo
Para algumas pessoas, esse erro de design assinado / não assinado no STL é motivo suficiente, para não usar o std :: vector, mas uma implementação própria.
fonte
for(int i = 0; i < get_size_of_stuff(); i++)
. Agora, claro, você pode não querer fazer muitos loops brutos, mas - vamos lá, você os usa também.x + 1 < y
equivalente ax < y - 1
, mas eles não estão com números inteiros não enviados. Isso pode facilmente introduzir bugs quando coisas são transformadas e assumidas como equivalentes.Use std :: size_t para indexar / contar matrizes no estilo C.
Para contêineres STL, você terá (por exemplo)
vector<int>::size_type
, que deve ser usado para indexar e contar elementos vetoriais.Na prática, eles geralmente são ints não assinados, mas isso não é garantido, especialmente ao usar alocadores personalizados.
fonte
std::size_t
normalmente éunsigned long
(8 bytes em sistemas de 64 bits) e nãounisgned int
(4 bytes).size_t
, pois os índices podem ser negativos. Alguém poderia usarsize_t
para sua própria instância de tal matriz, se não quiser ser negativo.+
em ponteiros, parece que esseptrdiff_t
é o único a ser usado para índices.vector<T>::size_type
(e idem para todos os outros contêineres), é realmente bastante inútil, porque é efetivamente garantido quesize_t
ele é - foi digitado eAllocator::size_type
, quanto a restrições em relação a contêineres, consulte 20.1.5 / 4 - em particular,size_type
deve sersize_t
edifference_type
deve serptrdiff_t
. Obviamente, o padrãostd::allocator<T>
atende a esses requisitos. Então, basta usar o mais curtosize_t
e não se preocupam com o resto do lote :)Em breve, a maioria dos computadores terá arquiteturas de 64 bits com SO de 64 bits executando programas operando em contêineres de bilhões de elementos. Em seguida, você deve usar em
size_t
vez deint
como índice de loop, caso contrário, seu índice contornará no elemento 2 ^ 32: th, nos sistemas de 32 e 64 bits.Prepare-se para o futuro!
fonte
long int
e não umint
. Sesize_t
é relevante em um sistema operacional de 64 bits, era igualmente relevante em um sistema operacional de 32 bits.Ao usar size_t, tenha cuidado com a seguinte expressão
Você ficará falso na expressão if, independentemente do valor que você tem para x. Levei vários dias para perceber isso (o código é tão simples que não fiz teste de unidade), embora demore apenas alguns minutos para descobrir a origem do problema. Não tenho certeza se é melhor fazer um elenco ou usar zero.
Ambas as formas devem funcionar. Aqui está o meu teste
A saída: i-7 = 18446744073709551614 (int) (i-7) = - 2
Eu gostaria dos comentários de outros.
fonte
(int)(i - 7)
é um underflow que é convertidoint
posteriormente, enquantoint(i) - 7
não é um underflow desde que você primeiro convertei
para umint
e depois subtrai7
. Além disso, achei seu exemplo confuso.size_t é retornado por várias bibliotecas para indicar que o tamanho desse contêiner é diferente de zero. Você o usa quando voltar: 0
No entanto, no seu exemplo acima, fazer um loop em size_t é um bug em potencial. Considere o seguinte:
o uso de números inteiros não assinados tem o potencial de criar esses tipos de problemas sutis. Portanto, imho prefiro usar size_t apenas quando interajo com contêineres / tipos que exigem isso.
fonte
size_t
é um tipo não assinado que pode conter o valor inteiro máximo para sua arquitetura, portanto, é protegido contra estouros de número inteiro devido a assinatura (int assinado0x7FFFFFFF
incremento de 1 fornecerá -1) ou tamanho curto (short sem sinal int 0xFFFF incrementado por 1 fornecerá a você 0)É usado principalmente na aritmética de indexação / loops / endereço de array e assim por diante. Funções como
memset()
e similares aceitamsize_t
apenas, porque teoricamente você pode ter um bloco de memória de tamanho2^32-1
(na plataforma de 32 bits).Para loops tão simples, não se preocupe e use apenas int.
fonte
size_t é um tipo integral não assinado, que pode representar o maior número inteiro no sistema. Use-o somente se você precisar de matrizes, matrizes muito grandes etc.
Algumas funções retornam um size_t e seu compilador avisará se você tentar fazer comparações.
Evite isso usando um tipo de dados assinado / não assinado apropriado ou simplesmente tipecast para um hack rápido.
fonte
size_t é sem sinal int. portanto, sempre que você quiser não assinado int, poderá usá-lo.
Eu uso quando eu quero especificar o tamanho da matriz, contador ect ...
fonte
size_t
pode ser um número inteiro de 64 bits sem sinal, enquanto em uma máquina de 32 bits é apenas um número inteiro sem sinal de 32 bits.