Почему QVector:: size возвращает int?

std::vector::size() возвращает size_type без знака и обычно то же самое, что и size_t, например. это 8 байтов на 64-битных платформах.

В constrast QVector::size() возвращает int, который обычно составляет 4 байта даже на 64-битных платформах, и при этом он подписан, что означает, что он может идти только на половину до 2 ^ 32.

Почему? Это кажется довольно нелогичным, а также технически ограничивающим, и хотя и не очень вероятно, что вам может понадобиться больше, чем 2 ^ 32 числа элементов, использование подписанных сокращений int, которые варьируются пополам без видимых веских причин. Возможно, чтобы избежать предупреждений компилятора для людей, слишком ленив объявить i как uint, а не int, который решил, что все контейнеры возвращают тип размера, который не имеет смысла, является лучшим решением? Причина не может быть такой глупой?

Ответы

Ответ 1

Это обсуждалось несколько раз, так как Qt 3 по крайней мере, и сторонник QtCore выразил, что некоторое время назад никаких изменений не произойдет до Qt 7, если он когда-либо будет.

Когда дискуссия продолжалась тогда, я подумал, что рано или поздно кто-то израсходует ее на Stack Overflow... и, вероятно, на нескольких других форумах и Q/A тоже. Попробуем демистифицировать ситуацию.

В общем, вам нужно понять, что здесь нет ничего лучше или хуже, поскольку QVector не является заменой std::vector. Последний не делает Copy-On-Write (COW) и поставляется с ценой. Он предназначен для другого варианта использования, в основном. Он в основном используется внутри приложений Qt и самой структуры, первоначально для QWidgets в ранние времена.

size_t имеет свою собственную проблему, после всего, что я укажу ниже.

Без того, чтобы я интерпретировал для вас сопровождающего, я просто приведу Тьяго непосредственно, чтобы нести сообщение официальная позиция:

По двум причинам:

1) он подписан, потому что нам нужны отрицательные значения в нескольких местах API: indexOf() возвращает -1, чтобы указать значение, не найденное; многие из "от" параметры могут принимать отрицательные значения для указания подсчета с конца. Так что даже если бы мы использовали 64-битные целые числа, нам понадобилась бы подписанная версия. Что POSIX ssize_t или Qt qintptr.

Это также позволяет избежать предупреждений об изменении знака, когда вы неявно конвертируете недостоверности в подписали:

-1 + size_t_variable        => warning
size_t_variable - 1     => no warning

2) это просто "int", чтобы избежать предупреждений о конверсиях или уродливого кода, связанного с использование целых чисел больше, чем int.

ю /qfilesystemiterator _unix.cpp

size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX);
if (maxPathName == size_t(-1))

ю /qfsfileengine.cpp

if (len < 0 || len != qint64(size_t(len))) {

ю /qiodevice.cpp

qint64 QIODevice::bytesToWrite() const
{
    return qint64(0);
}

return readSoFar ? readSoFar : qint64(-1);

Это было одно электронное письмо от Thiago, а затем есть еще один, где вы можете найти подробный ответ:

Даже сегодня программное обеспечение с памятью ядра более 4 ГБ (или даже 2 ГБ) является исключением, а не правилом. Будьте внимательны при просмотре размеры памяти некоторых инструментов процесса, поскольку они не представляют собой фактическую память использование.

В любом случае мы говорим здесь о том, что одна адресация контейнера более 2 ГБ памяти. Из-за неявного совместного использования и копирования на запись характер контейнеров Qt, которые, вероятно, будут крайне неэффективными. Тебе нужно быть очень осторожным при написании такого кода, чтобы избежать запуска COW и, следовательно, удвоение или ухудшение использования памяти. Кроме того, контейнеры Qt не обрабатывают OOM ситуации, поэтому, если вы находитесь где-то рядом с пределом памяти, контейнеры Qt являются неправильным инструментом для использования.

Самый большой процесс, который у меня есть в моей системе, - qtcreator, и он также является единственным один, который пересекает отметку 4 ГБ в VSZ (4791 МБ). Вы можете утверждать, что это что 64-битные контейнеры необходимы, но вы ошибаетесь:

  • У Qt Creator нет контейнера, требующего 64-битных размеров, это просто нужны 64-битные указатели

  • Он не использует 4 ГБ памяти. Это просто VSZ (сопоставленная память). Общая ОЗУ, доступное в настоящее время для Творца, составляет всего 348,7 МБ.

  • И он использует более 4 ГБ виртуального пространства, потому что он является 64-битным выражение. Связь причинно-следственных связей противоположна тому, что вы ожидать. В качестве доказательства этого я проверил, сколько виртуального пространства потребляется прокладка: 800 МБ. 32-битное приложение никогда не сделает этого, что 19,5% адресное пространство на 4 ГБ.

(заполнение - это виртуальное пространство, выделенное, но не подкрепленное чем-либо, оно только там, чтобы что-то еще не отображалось на эти страницы)

Переходя к этой теме еще дальше с ответами Тьяго, см. это:

  

Лично я ОЧЕНЬ счастлив, что размеры коллекции Qt подписаны. Кажется     орехи мне, что целочисленное значение, потенциально используемое в выражении, используя     вычитание будет неподписанным (например, size_t).

         

Целое число без знака не гарантирует, что выражение, включающее     что целое число никогда не будет отрицательным. Это только гарантирует, что результат     будет абсолютной катастрофой.

  

С другой стороны, стандарты C и С++ определяют поведение неподписанных переполнения и недогрузки.

Подписанные целые числа не переполняются и не переполняются. Я имею в виду, они делают, потому что типы и регистры процессора имеют ограниченное количество бит, но стандарты говорят, что они нет. Это означает, что компилятор всегда будет оптимизировать, полагая, или подтолкнуть их.

Пример:

for (int i = 1; i >= 1; ++i)

Это оптимизировано для бесконечного цикла, потому что целые числа со знаком не переполняются. Если вы измените его на unsigned, то компилятор знает, что он может переполняться и вернуться к нулю.

Некоторым людям это не понравилось: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30475

Ответ 2

unsigned значениями являются значения mod 2^n для некоторого n.

Подписанные числа - это ограниченные целые числа.

Использование неподписанных значений в качестве приближений для "положительных целых чисел" запускается в проблему, что общие значения находятся вблизи края домена, где значения без знака ведут себя не так, как простые целые числа.

Преимущество заключается в том, что беззнаковое приближение достигает более высоких положительных целых чисел, а под/переполнением хорошо определены (если они случайны, если рассматривать их как модель Z).

Но действительно, ptrdiff_t будет лучше, чем int.