С++ for-loop - size_type vs. size_t
В C++ Primer
книге, глава (3), существует следующий цикл for, который сбрасывает элементы в векторе до нуля.
for (vector<int>::size_type ix = 0; ix ! = ivec.size(); ++ix)
ivec[ix] = 0;
Почему используется vector<int>::size_type ix = 0
? Разве мы не можем сказать int ix = 0
? Какая польза от использования первой формы на второй?
Спасибо.
Ответы
Ответ 1
В стандарте С++ говорится:
size_type | unsigned integral type | a type that can represent the size of the largest object in the
allocation model
Затем он добавляет:
Реализации контейнеров описанных в этом Международном Стандарту разрешено предположить, что их параметр шаблона Allocator отвечает следующим двум дополнительным чем те, что указаны в таблице 32.
- Указатель членов typedef, const_pointer, size_type и Разница для T *, T const *, size_t и ptrdiff_t, соответственно
Так что, скорее всего, size_type
является typedef из size_t
.
И стандарт действительно определяет его как
template <class T>
class allocator
{
public:
typedef size_t size_type;
//.......
};
Поэтому наиболее важные моменты, которые необходимо отметить, следующие:
-
size_type
является интегралом unsigned
, а int
не обязательно unsigned
.: -)
- он может представлять наибольший индекс, потому что он неподписан.
Ответ 2
Да, вы можете использовать int
, но только тип vector<int>::size_type
гарантирует, что его тип может использоваться для индексации всех векторных элементов.
Он может быть или не быть такого же размера, как int
. Например, при компиляции для 64-разрядной Windows int
имеет 32-разрядную ширину, тогда как vector<int>::size_type
будет 64-битным.
Вместо использования довольно подробного vector<int>::size_type
, вы можете использовать std::size_t
, поскольку первый для него является typedef. Однако, если вам когда-либо случится изменить тип контейнера, тогда его size_type
может быть другого типа, и вам, возможно, придется изменить свой код, если он использует std::size_t
.
Ответ 3
vector<int>::size_type
- это тип, который гарантированно удерживает размер наибольшего vector
, который у вас может быть, и, следовательно, он гарантированно позволит вам индексировать все элементы vector
(поскольку индексы идут от 0 до размера -1); это тип, используемый для индексов и размеров во всех методах vector
.
Если у вас очень большие массивы, это может быть действительно актуально, так как другие целые типы могут переполняться (а если они signed
, все может стать довольно странным); даже если вы никогда не доберетесь до таких больших массивов, что это может иметь значение, это принципиально вещь чистоты кода; кроме того, ваш ix
имеет тот же тип ivec.size()
, поэтому вы не получите предупреждения для сравнения целых чисел без знака.
Фон: vector<T>::size_type
обычно typedef
для size_t
(я где-то читал, что на самом деле стандартный неявно налагает его на size_t
- EDIT: он вообще не подразумевается, см. ответ @Nawaz), который, в свою очередь, является возвращаемым типом оператора sizeof
. Это подразумевает, что он может содержать размер для самого большого объекта, который можно использовать в приложении на С++, поэтому он (достаточно) достаточно велик, чтобы индексировать массивы любого типа.
На самом деле, я использую size_t
(определенный в <cstddef>
) как индекс также для массивов в стиле C, и я думаю, что это хорошая практика по точно таким же причинам.
Кстати, вы также можете забыть тип, используемый для индексов, и просто пойти с итераторами:
for (vector<int>::iterator it = ivec.begin(); it != ivec.end(); ++it)
*it = 0;
или с итераторами + <algorithm>
:
std::fill(ivec.begin(), ivec.end(), 0);
Эти два параметра работают независимо от контейнера ivec
, поэтому вам не нужно ничего менять в коде, если вы решили изменить тип контейнера.
С помощью vector
вы также можете использовать метод assign
(как предлагается в другом ответе):
ivec.assign(ivec.size(), 0);
Ответ 4
Вы не должны использовать int
, потому что vector<int>::size_type
- это неподписанный тип, то есть вектор индексирует его элементы с неподписанным типом. int
однако является подписанным типом, и смешение подписи и неподписанных типов может привести к странным проблемам. (Хотя это не будет проблемой для небольшого n в вашем примере.)
Обратите внимание, что я считаю, что проще использовать size_t
(в отличие от T:: size_type) - меньше набирать текст и должно работать на всех реализациях.
Обратите внимание, что цикл for, который вы отправили:
for(size_t ix=0; ix != ivec.size(); ++ix) ...
лучше писать как:
for(size_t i=0, e=ivec.size(); i!=e; ++ix) ...
- не нужно вызывать size() каждую итерацию.