Использование int
более правильно с логической точки зрения для индексации массива.
unsigned
семантика в C и C ++ на самом деле не означает «не отрицательно», но больше похожа на «битовую маску» или «по модулю целое число».
Чтобы понять, почему unsigned
не подходит для «неотрицательного» числа, рассмотрите
- Добавляя, возможно, отрицательное целое число к неотрицательному, вы получаете неотрицательное целое число
- Разница двух неотрицательных целых чисел всегда является неотрицательным целым числом
- Умножая неотрицательное целое число на отрицательное целое, вы получаете неотрицательный результат
Очевидно, что ни одна из вышеперечисленных фраз не имеет никакого смысла ... но именно так работает семантика C и C ++ unsigned
.
Фактически использование типа unsigned
для размера контейнеров является ошибкой проектирования C ++, и, к сожалению, мы теперь обречены использовать этот неправильный выбор навсегда (для обратной совместимости). Вам может понравиться имя «unsigned», потому что оно похоже на «неотрицательное», но имя не имеет значения, и то, что считается семантическим ... и unsigned
очень далеко от «неотрицательного».
По этой причине при кодировании большинства циклов для векторов моя личная предпочтительная форма:
for (int i=0,n=v.size(); i<n; i++) {
...
}
(конечно, предполагая, что размер вектора не меняется во время итерации и что мне действительно нужен индекс в теле, так как в противном случае for (auto& x : v)...
лучше).
Это бегство от unsigned
как можно скорее и использование простых целых чисел позволяет избежать ловушек, которые являются следствием unsigned size_t
ошибки проектирования. Например, рассмотрим:
// draw lines connecting the dots
for (size_t i=0; i<pts.size()-1; i++) {
drawLine(pts[i], pts[i+1]);
}
Приведенный выше код будет иметь проблемы, если вектор pts
пуст, потому что pts.size()-1
- это огромное бессмысленное число в этом случае. Работа с выражениями, в которых a < b-1
отличается от a+1 < b
даже для часто используемых значений, похожа на танцы на минном поле.
Исторически оправданием наличия size_t
unsigned является возможность использовать дополнительный бит для значений, например, возможность иметь 65535 элементов в массивах вместо просто 32767 на 16-битных платформах. По моему мнению, даже в то время дополнительная стоимость этого неправильного семантического выбора не стоила выигрыша (а если 32767 элементов сейчас недостаточно, тогда 65535 не будет достаточно долго).
Беззнаковые значения хороши и очень полезны, но НЕ для представления размера контейнера или для индексов; для размера и индекса обычные целые числа со знаком работают намного лучше, потому что семантика - это то, что вы ожидаете.
Беззнаковые значения являются идеальным типом, когда вам нужно арифметическое свойство по модулю или когда вы хотите работать на битовом уровне.