Должен ли я итератировать вектор с помощью итератора или оператора доступа?



У меня есть вектор, объявленный как



std::vector<int> MyVector;
MyVector.push_back(5);
MyVector.push_back(6);
MyVector.push_back(7);


Как я должен использовать его в цикле for?



Повторяя его с помощью итератора?



for (std::vector<int>::iterator it=MyVector.begin(); it!=MyVector.end(); ++it)
{
std::cout << "Vector element (*it): " << *it << std::endl;
}


Или его итератором доступа?



for (std::vector<int>::size_type i=0; i<MyVector.size(); i++)
{
std::cout << "Vector element (i) : " << MyVector.at(i) << std::endl;
}


В примерах, которые я нашел в интернете, используются оба из них. Разве один из них превосходит другого при любых условиях? Если нет, то когда я должен предпочесть одного из них другому?

673   4  

4 ответов:

Первый формат: более общий формат для итерации по стандартным библиотечным контейнерам, поэтому он более распространен и интуитивно понятен. Если вам нужно изменить контейнер, то этот итерационный код остается unimpacted.It будет работать для каждого стандартного типа контейнера библиотеки, таким образом, он дает вам более общий код.

Во втором формате std::vector::at() проверяет границы каждый раз, когда он вызывается на каждой итерации, так что это может быть немного вредно для производительности. Эти накладные расходы отсутствуют в первом формате, так как не требуется проверка границ.Заметьте, что то же самое происходит и с использованием operator[].
Обратите внимание на задержку производительности, хотя это не так много, как вы заметите, если вы не работаете с огромными данными.

Использование std::vector's [] operator, вероятно, быстрее, потому что использование std::vector::at() внутри цикла for проверяет размер вектора дважды (в цикле for и в проверке границ std::vector::at ()).

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

Если вы используете C++11, используйте циклы на основе диапазона.

Во-первых, если у вас есть C++11, используйте диапазон на основе для:

for (auto i : MyVector)
{
    std::cout << i;
}

Или BOOST_FOREACH в C++03:

BOOST_FOREACH(int& i, MyVector)
{
  std::cout << i;
}

Или std::copy:

std::copy(MyVector.begin(),
          MyVector.end(), 
          std::ostream_iterator<int>(std::cout, "\n"));

Что касается вопроса под рукой, at() проверяет, что индекс находится в пределах границ и выдает исключение, если это не так. Так что не используйте его, если вам не нужна дополнительная проверка. Первый способ, который у вас есть, является стандартным и хорошо работает. Некоторые люди педантичны и даже пишут это так:

for (std::vector<int>::iterator it=MyVector.begin(), end = MyVector.end(); it!= end; ++it)
{
    std::cout << "Vector element (*it): " << *it << std::endl;
}

В приведенном выше примере я кэшировал итератор end вместо вызова end() каждый цикл. Действительно ли это влияет на производительность или нет, я не знаю.

Нет никакого "один выше другого" (за исключением того, что вы почти никогда хотите использовать at()-at() подходит только в том случае, если есть то, что вы действительно можете сделать, чтобы восстановить после ошибки). Использование итератор против индекса-это в основном стиль, и сообщение, которое вы проходящий. Более идиоматические с++ способ делать вещи будут итератор, но люди, происходящие из других слоев общества (например, математики) найдут индексацию более идиоматичной.

Есть там, где есть настоящий различие:

  • Идиома итератора будет работать с другими типами контейнеров. Этот может быть уместно, если есть реальная возможность, что вы используете другие стеклотара.

  • Идиома индексирования может использовать один индекс для нескольких различных стеклотара. Если вы перебираете несколько vector с одним и тем же размер, используя идиому индексирования, делает более ясным, что вы обращаетесь один и тот же элемент в каждом из vector. (Опять же, это, кажется, происходит чаще всего в математические приложения.)

  • Наконец, в любое время, когда вы действительно делаете случайный доступ или вычисляете элемент в любом случае, используя индексы, вероятно, более интуитивно понятен. (В в таких случаях вы, вероятно, захотите выполнить вычисления в int, только преобразование в size_t в последний момент.)

Comments

    Ничего не найдено.