С++: "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
на основе диапазона и полностью исключает проблему индексирования.