Trabajo con una gran cantidad de código de cálculo escrito en C ++ pensando en un alto rendimiento y una baja sobrecarga de memoria. Utiliza contenedores STL (principalmentevector
) mucho, e itera sobre esos contenedores casi en cada función.
El código iterativo se ve así:
for (int i = 0; i < things.size(); ++i)
{
// ...
}
pero produce la falta de coincidencia firmada / no firmada advertencia de (C4018 en Visual Studio).
Reemplazarlo int
con algún unsigned
tipo es un problema porque con frecuencia usamos pragmas OpenMP y requiere que el contador sea int
.
Estoy a punto de suprimir las (cientos de) advertencias, pero me temo que me he perdido alguna solución elegante al problema.
En iteradores . Creo que los iteradores son geniales cuando se aplican en lugares apropiados. El código con el que estoy trabajando nunca cambiará los contenedores de acceso aleatorio en list
o algo así (por lo que la iteración int i
ya es independiente del contenedor), y siempre necesitará el índice actual. Y todo el código adicional que necesita escribir (el iterador en sí y el índice) simplemente complica las cosas y ofusca la simplicidad del código subyacente.
fuente
int
.int
ystd::vector<T>::size_type
también pueden ser diferentes en tamaño y en firma. Por ejemplo, en un sistema LLP64 (como Windows de 64 bits),sizeof(int) == 4
perosizeof(std::vector<T>::size_type) == 8
.Respuestas:
Todo está en tu
things.size()
tipo. No lo esint
, perosize_t
(existe en C ++, no en C) que equivale a algún tipo sin signo "habitual", es decirunsigned int
para x86_32.El operador "menos" (<) no se puede aplicar a dos operandos de signo diferente. Simplemente no existen tales códigos de operación, y el estándar no especifica si el compilador puede realizar una conversión de signo implícita. Por lo tanto, solo trata el número firmado como sin firmar y emite esa advertencia.
Sería correcto escribirlo como
for (size_t i = 0; i < things.size(); ++i) { /**/ }
o incluso más rápido
for (size_t i = 0, ilen = things.size(); i < ilen; ++i) { /**/ }
fuente
size_t
. Lo esstd::vector< THING >::size_type
.std::size_t
ystd::vector<T>::size_type
.Idealmente, usaría una construcción como esta en su lugar:
for (std::vector<your_type>::const_iterator i = things.begin(); i != things.end(); ++i) { // if you ever need the distance, you may call std::distance // it won't cause any overhead because the compiler will likely optimize the call size_t distance = std::distance(things.begin(), i); }
Esto tiene la gran ventaja de que su código de repente se convierte en un contenedor independiente.
Y con respecto a su problema, si alguna biblioteca que usa requiere que la use
int
dondeunsigned int
encajaría mejor, su API es complicada. De todos modos, si está seguro de queint
siempre son positivos, puede hacer lo siguiente:int int_distance = static_cast<int>(distance);
Lo que especificará claramente su intención para el compilador: ya no lo molestará con advertencias.
fuente
static_cast<int>(things.size())
podrían ser las soluciones, si no hay otras.#pragma warning(push) #pragma warning(disable: 4018) /* ... function */ #pragma warning(pop)
) en lugar de usar una conversión innecesaria. (Los yesos esconden errores legítimos, ¿de acuerdo?;))Si no puede / no usar iteradores y si no puede / no utilizar
std::size_t
para el índice de bucle, hacer un.size()
aint
función de conversión de documentos que la asunción y realiza la conversión explícita para silenciar la advertencia del compilador.#include <cassert> #include <cstddef> #include <limits> // When using int loop indexes, use size_as_int(container) instead of // container.size() in order to document the inherent assumption that the size // of the container can be represented by an int. template <typename ContainerType> /* constexpr */ int size_as_int(const ContainerType &c) { const auto size = c.size(); // if no auto, use `typename ContainerType::size_type` assert(size <= static_cast<std::size_t>(std::numeric_limits<int>::max())); return static_cast<int>(size); }
Luego escribes tus bucles así:
for (int i = 0; i < size_as_int(things); ++i) { ... }
Es casi seguro que la instanciación de esta plantilla de función estará incorporada. En las compilaciones de depuración, se comprobará la suposición. En las versiones de lanzamiento, no lo será y el código será tan rápido como si llamaras a size () directamente. Ninguna versión producirá una advertencia del compilador, y es solo una pequeña modificación del ciclo idiomático.
Si también desea detectar fallas de suposición en la versión de lanzamiento, puede reemplazar la aserción con una declaración if que arroje algo como
std::out_of_range("container size exceeds range of int")
.Tenga en cuenta que esto resuelve tanto la comparación firmada / no firmada como el problema potencial
sizeof(int)
! =sizeof(Container::size_type)
. Puede dejar todas sus advertencias habilitadas y usarlas para detectar errores reales en otras partes de su código.fuente
Puedes usar:
Por ejemplo:
// simple class who output his value class ConsoleOutput { public: ConsoleOutput(int value):m_value(value) { } int Value() const { return m_value; } private: int m_value; }; // functional object class Predicat { public: void operator()(ConsoleOutput const& item) { std::cout << item.Value() << std::endl; } }; void main() { // fill list std::vector<ConsoleOutput> list; list.push_back(ConsoleOutput(1)); list.push_back(ConsoleOutput(8)); // 1) using size_t for (size_t i = 0; i < list.size(); ++i) { std::cout << list.at(i).Value() << std::endl; } // 2) iterators + distance, for std::distance only non const iterators std::vector<ConsoleOutput>::iterator itDistance = list.begin(), endDistance = list.end(); for ( ; itDistance != endDistance; ++itDistance) { // int or size_t int const position = static_cast<int>(std::distance(list.begin(), itDistance)); std::cout << list.at(position).Value() << std::endl; } // 3) iterators std::vector<ConsoleOutput>::const_iterator it = list.begin(), end = list.end(); for ( ; it != end; ++it) { std::cout << (*it).Value() << std::endl; } // 4) functional objects std::for_each(list.begin(), list.end(), Predicat()); }
fuente
También puedo proponer la siguiente solución para C ++ 11.
for (auto p = 0U; p < sys.size(); p++) { }
(C ++ no es lo suficientemente inteligente para auto p = 0, así que tengo que poner p = 0U ....)
fuente
for (auto thing : vector_of_things)
si no necesita el índice.size()
devuelve un tipo más grande que unsigned int, que es extremadamente común.Te daré una mejor idea
for(decltype(things.size()) i = 0; i < things.size(); i++){ //... }
decltype
esEntonces, deduce el tipo de
things.size()
yi
será un tipo igual quethings.size()
. Por lo tanto,i < things.size()
se ejecutará sin previo aviso.fuente
Tuve un problema similar. El uso de size_t no funcionaba. Probé el otro que funcionó para mí. (como a continuación)
for(int i = things.size()-1;i>=0;i--) { //... }
fuente
Yo solo haría
int pnSize = primeNumber.size(); for (int i = 0; i < pnSize; i++) cout << primeNumber[i] << ' ';
fuente