Я новичок в языке C ++. Я начал использовать векторы и заметил, что во всем коде, который я вижу, для итерации по вектору через индексы, первый параметр for
цикла всегда основан на векторе. В Java я мог бы сделать что-то вроде этого с ArrayList:
for(int i=0; i < vector.size(); i++){
vector[i].doSomething();
}
Есть ли причина, по которой я не вижу этого в C ++? Это плохая практика?
c++
coding-style
for-loop
iterator
Flynn
источник
источник
std::vector<int>::size_type i = 0;
, или, может бытьstd::vector<int>::iterator it = vector.begin();
?std::vector
? фактический вопрос, который здесь задают, таков : есть ли причина, по которой я не вижу этого в C ++? Это плохая практика? ака Почему я всегда вижу код в C ++, который использует итераторы при повторенииstd::vector
?Ответы:
Нет. Это неплохая практика, но следующий подход придает вашему коду определенную гибкость .
Обычно в пре-C ++ 11 коде для перебора элементов контейнера используются итераторы, что-то вроде:
Это потому, что это делает код более гибким.
Все стандартные контейнеры библиотеки поддерживают и предоставляют итераторы. Если на более позднем этапе разработки вам нужно переключиться на другой контейнер, то этот код не нужно менять.
Примечание. Написание кода, который работает со всеми возможными контейнерами стандартной библиотеки, не так прост, как может показаться.
источник
auto
.Причина, по которой вы не видите такой практики, весьма субъективна и не может дать однозначного ответа, потому что я видел много кода, который использует упомянутый вами способ, а не
iterator
код стиля.Ниже приведены причины, по которым люди не рассматривают
vector.size()
способ зацикливания:size()
каждый раз в состоянии цикла. Однако либо это не проблема, либо ее можно исправить тривиальноstd::for_each()
над самойfor
петлейstd::vector
другого (напримерmap
,list
) также потребует изменения механизма зацикливания, поскольку не все контейнеры поддерживаютsize()
стиль зацикливания.C ++ 11 предоставляет хорошие возможности для перемещения по контейнерам. Это называется «диапазон для цикла» (или «расширенный для цикла» в Java).
С небольшим кодом вы можете пройти через полное (обязательно!)
std::vector
:источник
#pragma omp parallel for
.Самый чистый способ перебора вектора - через итераторы:
или (эквивалент вышеупомянутого)
До C ++ 0x вы должны заменить auto на тип итератора и использовать функции-члены вместо глобальных функций начала и конца.
Это, наверное, то, что вы видели. По сравнению с упомянутым вами подходом преимущество заключается в том, что вы не сильно зависите от типа
vector
. Если вы переключитесьvector
на другой класс типа коллекции, ваш код, вероятно, все еще будет работать. Однако вы можете сделать нечто подобное и в Java. Концептуально нет большой разницы; C ++, однако, использует шаблоны для реализации этого (по сравнению с обобщениями в Java); следовательно, подход будет работать для всех типов, для которыхbegin
иend
функций определены, даже для не относящихся к классу типов, таких как статические массивы. Смотрите здесь: Как работает диапазон на основе для простых массивов?источник
begin
иend
, однако, является одной строкой.auto
с другой стороны было бы довольно сложно.Правильный способ сделать это:
Где T - тип класса внутри вектора. Например, если класс был CActivity, просто напишите CActivity вместо T.
Этот тип метода будет работать на каждом STL (не только на векторах, что немного лучше).
Если вы все еще хотите использовать индексы, способ:
источник
std::vector<T>::size_type
всегдаsize_t
? Это тип, который я всегда использую для этого.Есть несколько веских причин использовать итераторы, некоторые из которых упомянуты здесь:
Переключение контейнеров позже не делает ваш код недействительным.
то есть, если вы переходите от std :: vector к std :: list или std :: set, вы не можете использовать числовые индексы, чтобы получить значение, которое вы содержите. Использование итератора все еще действует.
Время отлова неверной итерации
Если вы измените свой контейнер в середине цикла, в следующий раз, когда вы будете использовать итератор, он выдаст недопустимое исключение итератора.
источник
Я был удивлен, что никто не упомянул, что итерация массива с целочисленным индексом облегчает вам написание ошибочного кода, подписывая массив с неправильным индексом. Например, если у вас есть вложенные циклы, используя
i
и вj
качестве индексов, вы можете неправильно индексировать массив с ,j
а неi
и, таким образом, вносить ошибку в программу.Напротив, другие формы, перечисленные здесь, а именно
for
цикл на основе диапазона и итераторы, намного менее подвержены ошибкам. Семантика языка и механизм проверки типов компилятора предотвратят случайный доступ к массиву с использованием неверного индекса.источник
В STL программисты используют
iterators
для обхода контейнеров, поскольку итератор является абстрактной концепцией, реализованной во всех стандартных контейнерах. Например,std::list
не имеетoperator []
вообще.источник
Использование оператора auto действительно упрощает его использование, так как не нужно беспокоиться о типе данных и размере вектора или любой другой структуре данных.
Итерация вектора с использованием auto и for loop
Вывод:
Вы также можете использовать этот метод для итерации наборов и списков. Использование auto автоматически определяет тип данных, используемый в шаблоне, и позволяет использовать его. Таким образом, даже если мы имели
vector
изstring
илиchar
тот же синтаксис будет работать нормальноисточник
Правильный способ итерации цикла и печати его значений следующие:
источник
Вот более простой способ итерации и печати значений в векторе.
источник
источник