Мы используем тип Integer, представляющий индексные переменные большую часть времени. Но в некоторых ситуациях мы вынуждены выбирать
std::vector<int> vec;
....
for(int i = 0; i < vec.size(); ++i)
....
Это заставит компилятор выдавать предупреждение о смешанном использовании переменных со знаком и без знака. если я сделаю индексную переменную как for( size_t i = 0; i < vec.size(); i++ )
, (или unsigned int
), это решит проблемы.
Когда речь идет о более конкретном использовании типов окон, большинство API-интерфейсов Windows имеют дело с DWORD (который определен как unsigned long).
Поэтому, когда я использую подобную итерацию, снова будет вызывать то же предупреждение. Теперь, если я переписать это как
DWORD dwCount;
....
for(DWORD i = 0; i < dwCount; ++i)
....
Я нахожу это немного странным. Это может быть проблема с восприятием.
Я согласен, что мы должны использовать индексную переменную одного типа, чтобы избежать проблем с диапазоном, которые могут возникнуть с индексными переменными. Например, если мы используем
_int64 i64Count; //
....
for(_int64 i = 0; i < i64Count; ++i)
....
Но в случае DWORD, или целых чисел без знака, есть ли проблемы при переписывании его как
for(int i = 0; (size_t)i < vec.size(); ++i)
Как большинство людей работают с похожими проблемами?
std::size_t
это более высокий ранг, чем int (или даже long). Если размер вектора когда-либо превыситstd::numeric_limits<int>::max()
, вы пожалеете, что использовали int.Ответы:
Vector имеет typedef, который говорит вам правильный тип для использования: -
Это почти всегда определяется как size_t, но вы не можете полагаться на это
источник
auto i = 0
? Это совсем не помогает,i
станьint
.using index_t = std::vector<int>::size_type;
.Для этого используйте итератор, а не
for
цикл.Для других, пока тип переменной имеет одинаковый размер,
static_cast
должен работать нормально (то есть,DWORD
чтобыint16_t
)источник
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i)
это боль писать. Наличиеfor (auto i = vec.begin();...
намного более читабельно. Конечно,foreach
также в C ++ 11.Случай, который вы описали, тоже не нравится в C ++. Но я научился жить с этим, либо используя
for( size_t i = 0; i < vec.size(); i++ )
или же
for( int i = 0; i < (int)vec.size(); i++ )
(конечно, последнее только тогда, когда нет риска получить некоторое переполнение int).
источник
Причина, по которой он предупреждает вас о сравнении подписанного и неподписанного, заключается в том, что подписанное значение, скорее всего, будет преобразовано в неподписанное, что может не соответствовать вашим ожиданиям
В вашем примере (по сравнению
int
сsize_t
)int
будет неявно преобразован вsize_t
(если только уint
него не будет большего диапазона, чемsize_t
). Таким образом, если значениеint
отрицательное, оно, вероятно, будет больше значения, с которым вы его сравниваете, из-за переноса. Это не будет проблемой, если ваш индекс никогда не будет отрицательным, но вы все равно получите это предупреждение.Вместо этого используйте неподписанный тип (например
unsigned int
,size_t
или, как рекомендует John B ,std::vector<int>::size_type
) для индексной переменной:Будьте осторожны при обратном отсчете:
Выше не будет работать, потому что
i >= 0
всегда верно, когдаi
не подписано. Вместо этого используйте « оператор стрелки » для циклов, которые ведут обратный отсчет:Как указывают другие ответы, вы обычно хотите использовать итератор для обхода
vector
. Вот синтаксис C ++ 11:источник
unsigned int
не достаточно большой, чтобы держать размер.Новая опция для C ++ 11, вы можете делать такие вещи, как следующие
for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}
и
for(decltype(dWord) i = 0; i < dWord; ++i) {...}
Хотя он повторяет чуть больше, чем это делает базовый цикл for, он не столь многословен, как до -11 способов определения значений, и последовательное использование этого шаблона будет работать для большинства, если не для всех возможных терминов, которые вы могли бы хочу сравнить с, что делает его отличным для рефакторинга кода. Это даже работает для простых случаев, подобных этому:
int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)
Кроме того, хотя вы должны использовать
auto
всякий раз, когда вы устанавливаетеi
какое-либо интеллектуальное значение (напримерvec.begin()
), оноdecltype
работает, когда вы устанавливаете постоянную, например, ноль, где auto просто разрешит это значение,int
потому что 0 - это простой целочисленный литерал.Если честно, я хотел бы увидеть механизм компилятора для расширения определения
auto
типа для инкрементаторов цикла, чтобы посмотреть на сравниваемое значение.источник
Я использую приведение к int, как в
for (int i = 0; i < (int)v.size(); ++i)
. Да, это некрасиво. Я виню в этом глупый дизайн стандартной библиотеки, где они решили использовать целые числа без знака для представления размеров. (Чтобы ... что? Расширить диапазон на один бит?)источник
if(v.size()-1 > 0) { ... }
вернуть true для пустого контейнера? Проблема в том, что размеры также часто используются в арифметике, особенно. с индексными контейнерами, что вызывает проблемы, учитывая, что они не подписаны. По сути, использование типов без знака для чего-либо еще, кроме 1) побитовых манипуляций или 2) модульной арифметики, вызывает проблемы.if(v.size() > 1) { ... }
поскольку это проясняет намерение, а в качестве дополнительного бонуса проблема со знаком / без знака становится недействительной), я вижу, как в некоторых конкретных случаях Подписание может быть полезным. Я стою исправлено.