Мне просто интересно, я должен использовать std::size_t
для петель и прочее вместо int
? Например:
#include <cstdint>
int main()
{
for (std::size_t i = 0; i < 10; ++i) {
// std::size_t OK here? Or should I use, say, unsigned int instead?
}
}
В целом, какова лучшая практика относительно того, когда использовать std::size_t
?
size_t
когда вы должны можете привести к ошибкам безопасности .ssize_t
для подписанных значений.size_t
тип результатаsizeof
оператора.Используйте
size_t
для переменных тот размер модели или индекс в массиве.size_t
передает семантику: вы сразу знаете, что она представляет размер в байтах или индекс, а не просто другое целое число.Кроме того, использование
size_t
для представления размера в байтах помогает сделать код переносимым.источник
size_t
Тип предназначен для определения размера чего - то , так что это естественно использовать его, например, получить длину строки , а затем обработки каждого символа:Вы же должны следить за граничные условия, конечно же , так что это тип без знака. Граница в верхней части, обычно не так важна , так как максимум, как правило , большой (хотя это возможно , чтобы получить там). Большинство людей просто используют
int
для такого рода вещей, потому что они редко имеют структуры или массивы, которые становятся достаточно большими, чтобы превышать возможности этогоint
.Но остерегайтесь таких вещей, как:
что приведет к бесконечному циклу из-за поведения оборачивания беззнаковых значений (хотя я видел компиляторы, предупреждающие об этом). Это также может быть облегчено с помощью (немного сложнее понять, но, по крайней мере, невосприимчив к проблемам с обертыванием):
Перемещая декремент в побочный эффект условия проверки продолжения после проверки, он выполняет проверку продолжения для значения перед декрементом, но все еще использует уменьшенное значение внутри цикла (именно поэтому цикл выполняется
len .. 1
вместо, а не изlen-1 .. 0
).источник
strlen
каждую итерацию цикла. :) Вы можете сделать что-то вроде этого:for (size_t i = 0, len = strlen(str); i < len; i++) ...
for (size_t i = strlen (str); i --> 0;)
-->
оператора «идет» (см. Stackoverflow.com/questions/1642028/… ). Включили ваше предложение в ответ.if (i == 0) break;
в конце цикла for (например,for (size_t i = strlen(str) - 1; ; --i)
(хотя мне нравится ваш, хотя я просто задаюсь вопросом, будет ли это работать так же хорошо).По определению
size_t
является результатомsizeof
оператора.size_t
был создан для ссылки на размеры.Количество раз, когда вы что-то делаете (10, в вашем примере) не зависит от размеров, так зачем использовать
size_t
?int
илиunsigned int
должно быть в порядке.Конечно, это также относится к тому, что вы делаете
i
внутри цикла. Если вы передадите его функции, которая принимаетunsigned int
, например, команду pickunsigned int
.В любом случае, я рекомендую избегать неявных преобразований типов. Сделайте все преобразования типов явными.
источник
size_t
это очень удобный способ определения размера элемента - длины строки, количества байтов, которые берет указатель и т. д. Он также переносим на разные платформы - вы обнаружите, что 64-битный и 32-битный оба хорошо работают с системными функциями иsize_t
- то, чтоunsigned int
может не делать (например, когда вы должны использоватьunsigned long
источник
короткий ответ:
почти никогда
длинный ответ:
Всякий раз, когда вам нужно иметь вектор char больше, чем 2gb в 32-битной системе. В любом другом случае использование подписанного типа намного безопаснее, чем использование неподписанного типа.
пример:
Подписанный эквивалент
size_t
естьptrdiff_t
, нетint
. Но использованиеint
по-прежнему намного лучше, чем size_t.ptrdiff_t
находитсяlong
на 32 и 64 - битных систем.Это означает, что вы всегда должны конвертировать в size_t и из него всякий раз, когда вы взаимодействуете с std :: Containers, что не очень красиво. Но на нативной конференции авторы c ++ отметили, что проектирование std :: vector с беззнаковым size_t было ошибкой.
Если ваш компилятор выдает предупреждения о неявных преобразованиях из ptrdiff_t в size_t, вы можете сделать это явным образом с помощью синтаксиса конструктора:
если вы хотите перебрать коллекцию без проверки границ, используйте диапазон на основе:
Вот несколько слов Бьярна Страуструпа (автора C ++) о том, как стать родным
Для некоторых людей эта ошибка дизайна со знаком / без знака в STL является достаточной причиной, чтобы не использовать std :: vector, а вместо этого собственную реализацию.
источник
for(int i = 0; i < get_size_of_stuff(); i++)
. Теперь, конечно, вы можете не захотеть делать много сырых циклов, но - давай, ты тоже их используешь.x + 1 < y
эквивалентноx < y - 1
, но они не с unigend целыми числами. Это может легко привести к ошибкам, когда вещи преобразуются, которые предполагаются эквивалентными.Используйте std :: size_t для индексации / подсчета массивов в стиле C.
Для контейнеров STL у вас будет (например)
vector<int>::size_type
, который должен использоваться для индексации и подсчета векторных элементов.На практике они обычно являются целыми числами без знака, но это не гарантируется, особенно при использовании пользовательских распределителей.
источник
std::size_t
обычноunsigned long
(8 байт в 64-битных системах), а неunisgned int
(4 байта).size_t
, поскольку индексы могут быть отрицательными. Можно использоватьsize_t
для собственного экземпляра такого массива, если вы не хотите идти отрицательным.+
в указателях, может показаться, чтоptrdiff_t
оно используется для индексов.vector<T>::size_type
(и то же самое для всех других контейнеров), это на самом деле довольно бесполезно, потому что он гарантированно гарантированно будетsize_t
- это typedef'd toAllocator::size_type
, а для ограничений на это в отношении контейнеров см. 20.1.5 / 4 - в частности,size_type
должен бытьsize_t
иdifference_type
должен бытьptrdiff_t
. Конечно, значение по умолчаниюstd::allocator<T>
удовлетворяет этим требованиям. Так что просто используйте корочеsize_t
и не мешайте остальной части партии :)Вскоре большинство компьютеров получат 64-битные архитектуры с 64-битными ОС: они работают с программами, работающими на контейнерах с миллиардами элементов. Затем вы должны использовать
size_t
вместоint
индекса цикла, иначе ваш индекс будет обернут в элементе 2 ^ 32: th, как в 32-, так и в 64-битной системах.Готовьтесь к будущему!
источник
long int
а неint
. Еслиsize_t
это применимо к 64-битной ОС, то же самое относится и к 32-битной ОС.При использовании size_t будьте осторожны со следующим выражением
Вы получите false в выражении if независимо от значения x. Мне потребовалось несколько дней, чтобы понять это (код настолько прост, что я не проводил модульное тестирование), хотя выяснение источника проблемы заняло всего несколько минут. Не уверен, что лучше сделать бросок или использовать ноль.
Оба способа должны работать. Вот мой тестовый прогон
Выход: i-7 = 18446744073709551614 (int) (i-7) = - 2
Я хотел бы комментарии других.
источник
(int)(i - 7)
это нижестоящее значение, которое преобразуется вint
последующее время, ноint(i) - 7
не является поточным, поскольку вы сначала конвертируетеi
вint
, а затем вычитаете7
. Кроме того, я нашел ваш пример запутанным.size_t возвращается различными библиотеками, чтобы указать, что размер этого контейнера не равен нулю. Вы используете его, когда вернетесь однажды: 0
Однако в приведенном выше примере зацикливание на size_t является потенциальной ошибкой. Учтите следующее:
использование целых чисел без знака может создать такие тонкие проблемы. Поэтому imho я предпочитаю использовать size_t только тогда, когда я взаимодействую с контейнерами / типами, которые требуют этого.
источник
size_t
это тип без знака, который может содержать максимальное целочисленное значение для вашей архитектуры, поэтому он защищен от целочисленных переполнений из-за знака (знак int,0x7FFFFFFF
увеличенный на 1, даст вам -1) или короткого размера (unsigned short int 0xFFFF, увеличенный на 1, даст вам 0).Он в основном используется для индексации массивов / циклов / адресной арифметики и так далее. Такие функции, как
memset()
и одинаковые, принимаютsize_t
только потому, что теоретически у вас может быть блок памяти размером2^32-1
(на 32-битной платформе).Для таких простых циклов не беспокойтесь и используйте только int.
источник
size_t - это целочисленный тип без знака, который может представлять наибольшее целое число в вашей системе. Используйте его только если вам нужны очень большие массивы, матрицы и т. Д.
Некоторые функции возвращают size_t, и ваш компилятор предупредит вас, если вы попытаетесь сделать сравнение.
Избегайте этого, используя соответствующий тип данных со знаком / без знака или просто приведение типа для быстрого взлома.
источник
size_t без знака int. поэтому, когда вы хотите unsigned int, вы можете использовать его.
Я использую его, когда хочу указать размер массива, счетчик и т. Д ...
источник
size_t
может быть 64-разрядное целое число без знака, а на 32-разрядной машине это только 32-разрядное целое число без знака.