c++ - qvectors - ¿Por qué QVector:: size devuelve int?
qlist (2)
Esto ha sido discutido varias veces desde Qt 3 al menos y el mantenedor de QtCore expresó que hace un tiempo no ocurriría ningún cambio hasta Qt 7 si alguna vez lo hace.
Cuando la discusión se desarrollaba en aquel entonces, pensé que alguien lo mencionaría en Stack Overflow tarde o temprano ... y probablemente en otros foros y Q / A, también. Tratemos de desmitificar la situación.
En general, debe comprender que no hay mejor o peor, ya que QVector
no reemplaza a std::vector
. Este último no hace ninguna Copia en escritura (COW) y eso tiene un precio. Está destinado a un caso de uso diferente, básicamente. Se utiliza principalmente dentro de las aplicaciones Qt y el propio framework, inicialmente para QWidgets en los primeros tiempos.
size_t
tiene su propio problema, después de todo lo que indicaré a continuación.
Sin que yo le interprete al mantenedor, solo citaré a Thiago directamente para llevar el mensaje de la postura oficial sobre:
Por dos razones:
1) está firmado porque necesitamos valores negativos en varios lugares de la API: indexOf () devuelve -1 para indicar un valor no encontrado; muchos de los parámetros "de" pueden tomar valores negativos para indicar el conteo desde el final. Así que incluso si usáramos enteros de 64 bits, necesitaríamos la versión firmada. Ese es el POSIX ssize_t o el Qt qintptr.
Esto también evita las advertencias de cambio de signo cuando convierte implícitamente los unsigneds en firmados:
-1 + size_t_variable => warning
size_t_variable - 1 => no warning
2) es simplemente "int" para evitar las advertencias de conversión o el código feo relacionado con el uso de enteros más grandes que int.
io / qfilesystemiterator_unix.cpp
size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX);
if (maxPathName == size_t(-1))
io / qfsfileengine.cpp
if (len < 0 || len != qint64(size_t(len))) {
io / qiodevice.cpp
qint64 QIODevice::bytesToWrite() const
{
return qint64(0);
}
return readSoFar ? readSoFar : qint64(-1);
Ese fue un correo electrónico de Thiago y luego hay otro donde puede encontrar una respuesta detallada:
Incluso hoy en día, el software que tiene una memoria central de más de 4 GB (o incluso 2 GB) es una excepción, más que la regla. Tenga cuidado al mirar los tamaños de memoria de algunas herramientas de proceso, ya que no representan el uso real de la memoria.
En cualquier caso, estamos hablando de tener un solo contenedor que dirija más de 2 GB de memoria. Debido a la naturaleza implícitamente compartida y copia en escritura de los contenedores Qt, probablemente será altamente ineficiente. Debe tener mucho cuidado al escribir dicho código para evitar desencadenar COW y, por lo tanto, duplicar o empeorar el uso de la memoria. Además, los contenedores Qt no manejan las situaciones de OOM, por lo que si está cerca del límite de su memoria, los contenedores Qt son la herramienta incorrecta.
El proceso más grande que tengo en mi sistema es qtcreator y también es el único que cruza la marca de 4 GB en VSZ (4791 MB). Podría argumentar que es una indicación de que se requieren contenedores de 64 bits, pero se equivocaría:
Qt Creator no tiene ningún contenedor que requiera tamaños de 64 bits, simplemente necesita punteros de 64 bits
No está utilizando 4 GB de memoria. Eso es sólo VSZ (memoria asignada). El total de RAM actualmente accesible para el creador es simplemente de 348.7 MB.
Y está utilizando más de 4 GB de espacio virtual porque es una aplicación de 64 bits. La relación causa-efecto es lo opuesto a lo que cabría esperar. Como prueba de esto, verifiqué la cantidad de espacio virtual que consume el relleno: 800 MB. Una aplicación de 32 bits nunca haría eso, eso es el 19.5% del espacio direccionable en 4 GB.
(el relleno es un espacio virtual asignado pero no está respaldado por nada; solo está ahí para que otra cosa no se asigne a esas páginas)
Al abordar este tema aún más con las respuestas de Thiago, vea esto:
Personalmente, estoy MUY feliz de que los tamaños de la colección Qt estén firmados. Me parece absurdo que un valor entero potencialmente usado en una expresión que usa la resta esté sin firmar (por ejemplo, size_t).
Un entero sin signo no garantiza que una expresión que involucre a ese entero nunca sea negativa. Solo garantiza que el resultado será un desastre absoluto.
Por otro lado, los estándares C y C ++ definen el comportamiento de los desbordamientos y subflujos sin firmar.
Los enteros firmados no se desbordan ni se desbordan. Quiero decir, lo hacen porque los tipos y los registros de la CPU tienen un número limitado de bits, pero las normas dicen que no. Eso significa que el compilador siempre se optimizará suponiendo que no se desborden o desborden.
Ejemplo:
for (int i = 1; i >= 1; ++i)
Esto se optimiza para un bucle infinito porque los enteros con signo no se desbordan. Si lo cambia a unsigned, entonces el compilador sabe que puede desbordarse y volver a cero.
A algunas personas no les gustó eso: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475
std::vector::size()
devuelve un size_type
que no está firmado y generalmente es lo mismo que size_t
, por ejemplo, es de 8 bytes en plataformas de 64 bits.
En QVector::size()
, QVector::size()
devuelve un int
que suele ser de 4 bytes incluso en plataformas de 64 bits, y en ese momento está firmado, lo que significa que solo puede ir hasta la mitad a 2 ^ 32.
¿Porqué es eso? Esto parece bastante ilógico y también técnicamente limitante, y aunque no es muy probable que alguna vez necesite más de 2 ^ 32 elementos, el uso de cortes int firmados que se extienden a la mitad sin una buena razón aparente. ¿Quizás para evitar advertencias del compilador para personas demasiado perezosas para declarar i
como uint
lugar de int
que decidió que hacer que todos los contenedores devuelvan un tipo de tamaño que no tenga sentido es la mejor solución? ¿La razón no podría ser tan tonta?
unsigned
números unsigned
son valores mod 2^n
para algunos n
.
Los números firmados son enteros delimitados.
El uso de valores sin signo como aproximaciones para "enteros positivos" se encuentra con el problema de que los valores comunes están cerca del borde del dominio donde los valores sin signo se comportan de manera diferente a los enteros simples.
La ventaja es que la aproximación sin signo alcanza números enteros positivos más altos, y el subdesbordamiento / desbordamiento están bien definidos (si se considera aleatorio cuando se considera un modelo de Z).
Pero en realidad, ptrdiff_t
sería mejor que int
.