С++: "vector <int>:: size_type variable" - в чем смысл объявления таким образом?

Я думаю, что это очень простой вопрос, но я не мог просто понять это.

Я использовал для использования массивов в С++, но теперь я начинаю изучать векторы. Я делал тестовый код, и я наткнулся на вопрос.

Прежде всего, вот код, который я сделал:

#include <iostream>
#include <vector>
#include <numeric>
using namespace std;

int main(){
  vector<double> score(10);

  for(vector<double>::size_type i=0;i<20;i++) {
    cout<<"Enter marks for student #"<<i+1<<":"<<flush;
    cin>>score[i];
  }

  double total = accumulate(score.begin(), score.end(),0);

  cout<<"Total score:"<<total<<endl<<"Average score:"<<total/score.size()<<flush;

  return 0;
}

В предложении for в строке # 9 я объявляю i как тип vector<double>::size_type (потому что мне сказали это сделать). Я протестировал код с типом, упомянутым выше, на int, и он работал отлично. Почему vector<double>::size_type предпочтительнее по сравнению с int?

Ответы

Ответ 1

size_type гарантированно будет достаточно большим для наибольшего поддерживаемого размера вектора vector::max_size(). int нет: на многих распространенных платформах int имеет 32 бита, а max_size() значительно больше 2 31.

Если вы знаете, что размер (и всегда будет) маленьким числом, например 20, то вы можете избежать использования int или любого другого целочисленного типа вместо size_type. Если бы вы изменили программу, например, чтобы прочитать размер от ввода, тогда это пошло бы ужасно неправильно, если бы это значение было больше, чем INT_MAX; используя size_type, он будет продолжать работать для любого значения до max_size(), которое вы можете легко проверить.

Ответ 2

Вложенный тип vector<double>::size_type относится к возвращаемому значению для различных методов vector, таких как .size(), поэтому предпочтение в этом случае использовать соответствующие типы (int = 0 обычно приводит к предупреждению о несоответствии знака). Например.

for (vector<double>::size_type i = 0; i < score.size(); ++i) { // types match
  // ...
}

for (int i = 0; i < score.size(); ++i) { // types mismatch
  // ...
}

std::vector::size_type должен быть достаточно большим, чтобы отображать максимальное количество элементов, которые могут содержаться в контейнере, в данном случае vector<double>::max_size(). В общем случае он отображается на size_t.

В вашем случае нет явной причины использовать vector<double>::size_type (хотя было бы технически лучше использовать size_type), поскольку цикл работает от 0 до 20, а оба - int. Следовательно, было бы нормально.

for (int i = 0; i < 20; ++i) { // loops 20 times
  // ...
}

Дополнительные примечания:

Использовать петли на основе итератора по индексам:

for (vector<double>::iterator i = score.begin(); i != score.end(); ++i) {
  // ...
}

Он не был помечен как С++ 11, но если это возможно, диапазон, основанный на циклах, имеет дело с большим количеством этого.

for (double& i : score) {
  // ...
}

Или даже используя for_each с лямбдой.

Ответ 3

vector size_type - это то, что используется вектором для сравнения размеров. Если у вас был цикл, который использовал int в качестве счетчика и сравнивал его с фактическим фактическим размером, вы получили предупреждения от компилятора о сопоставлениях с сопоставленными или беззнаковыми целями:

for( int i=0; i<score.size(); i++ ){  // <-- signed vs. unsigned comparisons
    // do something...
}

Ответ 4

Ваша проблема в два раза.

Во-первых, вы пишете за пределами std::vector - std::vector имеет 10 элементов, и вы пишете до 20.

Чтобы исправить это и следовать принципу "Не повторяй себя", вы изменили бы свой код следующим образом:

int main(){
  std::vector<double> score(20);

  for(std::vector<double>::size_type i=0;i<score.size();i++) {

где я сделал больше vector и использовал его размер, чтобы определить, сколько писать.

Теперь, когда мы пытаемся заменить это длинное предложение на int:

int main(){
  std::vector<double> score(20);

  for(int i=0;i<score.size();i++) {

получаем сглаженное/беззнаковое сравнение (возможно):

i<score.size()

где score.size() - неподписанное значение типа std::vector<double>::size_type, а i - int.

Компиляторы часто дают предупреждения в этих случаях, так как очень легко получить бессмысленные результаты (если i < 0, сравнение обычно приведет к тому, что отрицательное число будет больше, чем положительное!) Кроме того, если размер vector больше максимального значения int (в некоторых системах, как минимум, 32767, обычно не менее 2147483647, а иногда и намного больше - это значение, которое компилятор достаточно легко выбрать для себя, стандарт С++ не указывает его полностью), цикл не удастся эффектно.

Теперь, когда тип std::vector<double>::size() равен std::vector<double>::size_type, это (в каждой реализации, которую я испытал) просто std::size_t. Так что это более короткий способ сказать это:

  for(std::size_t i=0;i<score.size();i++) {

(std::size_t определяется в <cstddef> как в стороне).

Если вы программируете на С++ 11, вы можете сделать это лучше:

int i=0;
for(double& student:score) {
  std::cout<<"Enter marks for student #"<<++i<<":"<<std::flush;
  std::cin>>student;
}

который представляет собой цикл for на основе диапазона и полностью исключает проблему индексирования.