C ++ for-loop - размер_типа против размера_т - PullRequest
15 голосов
/ 31 января 2011

В книге C++ Primer, глава (3), есть следующий цикл for, который сбрасывает элементы в векторе до нуля.Разве мы не можем сказать int ix = 0?В чем преимущество использования первой формы на второй?

Спасибо.

Ответы [ 4 ]

16 голосов
/ 31 января 2011

Стандарт C ++ гласит:

 size_type  |  <b>unsigned integral type</b>  |  a type that <b>can represent the size of the largest object</b> 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. : -)
  • может представлять самый большой индекс, потому что он без знака.
12 голосов
/ 31 января 2011

Да, вы можете использовать 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.

9 голосов
/ 31 января 2011

vector<int>::size_type - это тип, который гарантированно будет содержать размер самого большого vector, который у вас может быть, и, таким образом, он гарантированно позволит вам индексировать все элементы vector (поскольку индексы изменяются от 0 до размера-1);это тип, используемый для индексов и размеров во всех методах vector.

Если у вас очень большие массивы, это может быть актуально, поскольку другие целочисленные типы могут переполняться (и если они являются типами signed)все может стать довольно странным);даже если вам никогда не удастся получить настолько большие массивы, чтобы это могло иметь значение, это принципиально важно для чистоты кода;кроме того, ваш ix имеет тот же тип ivec.size(), поэтому вы не получаете предупреждений о сравнении целых чисел со знаком и без знака.

Фон : vector<T>::size_type обычно typedef для size_t (я где-то читал, что на самом деле стандарт неявно налагает его на size_t - РЕДАКТИРОВАТЬ : это вообще не подразумевается, см. @ Nawaz *Ответ 1023 *), который, в свою очередь, является типом возврата оператора sizeof.Это неявно говорит о том, что он может содержать размер самого большого объекта, используемого в приложении C ++, поэтому он, безусловно, (достаточно) достаточно большой, чтобы индексировать массивы любого типа.

На самом деле, я использую size_t (определенов <cstddef>) в качестве индекса и для массивов в стиле С, и я думаю, что это хорошая практика по тем же причинам.

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

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);
3 голосов
/ 31 января 2011

Не следует использовать 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 () на каждой итерации.

...