Usamos el tipo Integer para representar variables de índice la mayor parte del tiempo. Pero en algunas situaciones, nos vemos obligados a elegir
std::vector<int> vec;
....
for(int i = 0; i < vec.size(); ++i)
....
Esto hará que el compilador genere la advertencia de que el uso mixto de variables con signo / sin signo. si hago que el índice sea variable como for( size_t i = 0; i < vec.size(); i++ )
, (o an unsigned int
) solucionará los problemas.
Cuando es más específico usar tipos de Windows, la mayoría de las API de Windows se ocupan de DWORD (que se definió como sin signo durante mucho tiempo).
Entonces, cuando uso una iteración similar, nuevamente causaré la misma advertencia. Ahora si lo reescribo como
DWORD dwCount;
....
for(DWORD i = 0; i < dwCount; ++i)
....
Esto me parece un poco raro. Puede ser el problema con las percepciones.
Estoy de acuerdo en que se supone que debemos usar el mismo tipo de variable de índice para evitar que los problemas de rango puedan ocurrir con las variables de índice. Por ejemplo, si estamos usando
_int64 i64Count; //
....
for(_int64 i = 0; i < i64Count; ++i)
....
Pero en el caso de DWORD, o enteros sin signo, ¿hay algún problema para reescribirlo como
for(int i = 0; (size_t)i < vec.size(); ++i)
¿Cómo trabaja la mayoría de las personas con problemas similares?
std::size_t
es un rango más alto que int (o incluso largo). Si el tamaño del vector excede alguna vezstd::numeric_limits<int>::max()
, lamentará haber usado int.Respuestas:
vector tiene un typedef que le dice el tipo correcto a usar: -
Sin embargo, casi siempre se define como size_t, pero no puede confiar en eso
fuente
auto i = 0
? Eso no ayuda en absoluto,i
convertirse en unint
.using index_t = std::vector<int>::size_type;
.Use un iterador para esto, no un
for
bucle.Para los demás, siempre que el tipo de variable sea del mismo tamaño,
static_cast
debería funcionar bien (es decir,DWORD
aint16_t
)fuente
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i)
Es un dolor de escribir. Tenerfor (auto i = vec.begin();...
es mucho más legible. Por supuesto,foreach
también está en C ++ 11.El caso que describiste también es una de las cosas que no me gustan en C ++. Pero he aprendido a vivir con eso, ya sea usando
for( size_t i = 0; i < vec.size(); i++ )
o
for( int i = 0; i < (int)vec.size(); i++ )
(por supuesto, esto último solo cuando no hay riesgo de tener un desbordamiento int).
fuente
La razón por la que le advierte sobre la comparación entre firmado y sin signo es porque el valor con signo probablemente se convertirá en sin signo, que podría no ser lo que espera.
En su ejemplo (en comparación
int
consize_t
),int
se convertirá implícitamente asize_t
(a menos que deint
alguna manera tenga un rango mayor quesize_t
). Por lo tanto, si el valorint
es negativo, es probable que sea mayor que el valor con el que lo está comparando debido a la envoltura. Esto no será un problema si su índice nunca es negativo, pero igual recibirá esa advertencia.En su lugar, utilice un tipo sin signo (por ejemplo
unsigned int
,size_t
o, como John B recomienda ,std::vector<int>::size_type
) para la variable de índice:Sin embargo, tenga cuidado al hacer la cuenta regresiva:
Lo anterior no funcionará porque
i >= 0
siempre es cierto cuandoi
no está firmado. En su lugar, use el " operador de flecha " para los bucles que cuentan hacia atrás:Como señalan otras respuestas, normalmente desea utilizar un iterador para atravesar a
vector
. Aquí está la sintaxis de C ++ 11:fuente
unsigned int
no sea lo suficientemente grande como para contener el tamaño.Una nueva opción para C ++ 11, puede hacer cosas como las siguientes
for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}
y
for(decltype(dWord) i = 0; i < dWord; ++i) {...}
Si bien se repite un poco más de lo que lo haría el bucle for básico, no es tan extenso como las formas anteriores a '11 de especificar valores, y usar este patrón de manera consistente funcionará para la mayoría, si no todos, los posibles términos que quiere comparar, lo que lo hace ideal para la refactorización de código. Incluso funciona para casos simples como este:
int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)
Además, si bien debe usarlo
auto
siempre que esté configurandoi
un valor inteligente (comovec.begin()
),decltype
funciona cuando está configurando una constante como cero, donde auto solo resolvería esoint
porque 0 es un literal entero simple.Para ser honesto, me gustaría ver un mecanismo compilador para extender la
auto
determinación de tipo para los incrementadores de bucle para ver el valor que se compara.fuente
Yo uso un elenco para int, como en
for (int i = 0; i < (int)v.size(); ++i)
. Si, es feo. Lo culpo por el estúpido diseño de la biblioteca estándar donde decidieron usar enteros sin signo para representar tamaños. (Para ... ¿qué? ¿Extender el rango un bit?)fuente
if(v.size()-1 > 0) { ... }
devolver verdadero para un contenedor vacío? El problema es que los tamaños también se usan a menudo en aritmética, especialmente. con contenedores basados en índices, que están pidiendo problemas dado que no están firmados. Básicamente, el uso de tipos sin signo para otra cosa que no sea 1) manipulaciones bit a bit, o 2) la aritmética modular es un problema.if(v.size() > 1) { ... }
ya que eso aclara la intención, y como una ventaja adicional, el tema de firmado / no firmado se anula), sí veo cómo en algunos casos específicos La firma puede ser útil. Estoy corregido.