Давайте сделаем самый простой пример из возможных:
Формулировка 1:
std::vector<int> vec;
// add 10E11 elements
for(std::size_t n = 0; n < vec.size(); ++n)
// ...
Формулировка 2:
std::vector<int> vec;
// add 10E11 elements
for(std::vector<int>::size_type n = 0; n < vec.size(); ++n)
// ...
Естественно, unsigned int
или любые неподходящие типы данных здесь не работают, и мы должны скомпилировать x64. Мой вопрос: есть ли случай, когда первая формулировка может привести к проблемам, или мы можем безопасно всегда писать это в этой гораздо более короткой записи? Мне также было бы интересно в подобных настройках, если они тривиальны для покрытия (x86, любой другой контейнер, другие приложения size_type
).
std::vector
гарантирует, что указатели являются действительными итераторами для всей своей последовательности, потому что vector::data
возвращает «Указатель такой, что [data(), data() + size())
является допустимым диапазоном. «Это дополнение указателя, которое определено над std::ptrdiff_t
, которая является подписанной версией std::size_t
,
Кроме того, [iterator.requirements.general] / 6 применяется:
… Для интегральных значений
n
и разыменовываемые значения итератораa
а также(a + n)
,*(a + n)
эквивалентно*(addressof(*a) + n)
…
Это возможно для vector::size_type
быть более узкий чем std::size_t
например, 32 бита в 64-битной системе. Но я не о чем беспокоюсь.
Хотя это относится ко всем распространенным реализациям, стандарт на это не дает никаких гарантий. Что гарантировано, так это std::vector<T>::size_type
является определенным в реализации целочисленным типом без знака.
Рекомендации:
23.2.1 Общие требования к контейнерам [container.requirements.general]
X :: size_type [is] без знака
целочисленный тип
и 23.3.6.1 Обзор вектора шаблона класса [vector.overview] §2
typedef implementation-defined size_type; // see 23.2
В то время как std::vector::size_type
обычно std::size_t
, нет никаких гарантий, что это должно. Безопаснее использовать
for(std::vector<int>::size_type n = 0; n < vec.size(); ++n)