Перебор цикла for в C++ и сравнение итератора с отрицательным числом. Может ли int хранить неподписанный int?

Я хочу:

  1. Сохраните значение индекса по умолчанию "-1". Если я закончу итерацию по вектору (используя цикл for), а значение индекса по-прежнему равно «-1», я знаю, что ни одно из значений, проверенных моим циклом for, не совпадает.
  2. Если найдено подходящее значение, обновите значение индекса, чтобы оно соответствовало индексу значения в векторе, который я итерирую.

Пример:

int index = -1;
for (int i; i < vector.size(); i++){
    if (vector[i] == 1) {
        index = i;
        break;
    }
}

Однако я всегда получаю предупреждение о «сравнении целочисленных выражений со знаком и без знака» от for (int i; i < vector.size(); i++). К сожалению, я не могу просто использовать unsigned integer index = -1, поскольку целые числа без знака не могут хранить отрицательные значения. Безопасно ли хранить значение unsigned int i в int index или мне нужно найти другой метод сравнения? В этом случае я бы изменил цикл for на for (unsigned int i; i < vector.size(); i++), но оставил остальную часть кода то же.

Я мог бы использовать отдельную логическую переменную, но использование дополнительной переменной каждый раз, когда я сталкиваюсь с этим сценарием, кажется более загроможденным. Это будет выглядеть примерно так:

bool found = false;
unsigned int index = -1;
for (unsigned int i; i < vector.size(); i++){
    if (vector[i] == 1) {
        index = i;
        bool = true;
        break;
    }
}

person Camoen    schedule 05.04.2018    source источник


Ответы (6)


Вместо этого используйте итератор, и в качестве бонуса вам вообще не нужно писать цикл:

auto it = std::find( vector.begin(), vector.end(), 1 );
if( it == vector.end() ) {
    ... // not found
}

вы можете использовать итератор с явным циклом, если хотите.

auto it = vector.begin();
for( ; it != vector.end(); ++it ) {
     if( *it == 1 ) break;
}

if( it == vector.end() ) {
    ... // not found
}
auto index = std::distance( vector.begin(), it );
person Slava    schedule 05.04.2018
comment
Это правильный способ решения проблемы (определение существования элемента в векторе и, если он существует, получение индекса), но он не отвечает на исходный вопрос: можно ли сохранить unsigned int в int. На что ответ положительный, но вы можете получить исключение во время выполнения, если столкнетесь с целочисленным переполнением. - person stevendesu; 05.04.2018
comment
Вопрос @stevendesu по теме не так уж много (например, логический флаг также не позволяет хранить), поэтому я не уверен, какой вопрос правильный. - person Slava; 05.04.2018

Вы можете использовать специальное значение:

unsigned int index = (unsigned int)-1;
for (unsigned int i; i < vector.size(); i++){
    if (vector[i] == 1) {
        index = i;
        break;
    }
}

Компилятор установит (unsigned int)-1 как наибольшее значение, которое соответствует беззнаковому целому числу, что для 32-битного представления равно 4 294 967 295.

person Ripi2    schedule 05.04.2018

Я рекомендую добавить функцию:

bool contains(std::vector<int> const& vec, int item);

Затем клиентский код можно упростить до:

if ( contains(vector, 1) )
{
   ...
}
else
{
   ...
}

Реализация contains может принимать несколько форм.

  1. Используйте цикл for на основе индекса.
  2. Используйте цикл range-for.
  3. Используйте std::find.

Ни один из них не требует, чтобы вы сохраняли значение дозорного индекса.

Использование цикла for на основе индекса

bool contains(std::vector<int> const& vector, int item)
{
   for (size_t i = 0; i < vector.size(), ++i )
   {
      if ( vector[i] == item )
      {
         return true;
      }
   }
   return false;
}

Использование цикла range-for

bool contains(std::vector<int> const& vector, int item)
{
   for (auto x : vector)
   {
      if ( x == item )
      {
         return true;
      }
   }
   return false;
}

Использование std::find

bool contains(std::vector<int> const& vector, int item)
{
   return (std::find(vector.begin(), vector.end(), item) != vector.end());
}
person R Sahu    schedule 05.04.2018

Вы можете работать в size_t, нет необходимости переключаться на int. Таким образом гарантируется, что ваш индекс будет совместим с размером вашего вектора. Также, если вы все еще хотите сравнить с -1, вы можете это сделать.

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = { 0,2,3,4 };

    size_t index = -1;

    for (size_t i = 0, n = v.size(); i < n; ++i)
    {
        if (v[i] == 1)
        {
            index = i;
            break;
        }
    }

    if (static_cast<int>(index) == -1)
    {
        std::cout << "not found" << std::endl;
    }
    else
        std::cout << index << std::endl;
}
person Killzone Kid    schedule 05.04.2018

Вы должны использовать size_t для адресации в std::vectors. Подумайте о том дне, когда кто-то передаст вашей функции вектор, содержащий ровно 2^64 элемента.

Лично я нахожу логическое значение намного чище, поскольку оно делает намерение явным.

person Jeffrey    schedule 05.04.2018
comment
Ответ @Slava лучше, но если вам когда-нибудь понадобится произвольный доступ к вашему вектору, используйте size_t. :-) - person Jeffrey; 05.04.2018

Ваш первый подход подходит для небольших чисел.

Просто используйте статическое приведение, чтобы прямо сказать компилятору, что вы делаете это намеренно

    index = static_cast<int>(i);

и в цикле используйте unsigned int

person atrelinski    schedule 05.04.2018