Как правильно перебирать вектор в C ++?
Рассмотрим эти два фрагмента кода, этот работает нормально:
for (unsigned i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
и этот:
for (int i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
который генерирует warning: comparison between signed and unsigned integer expressions
.
Я новичок в мире C ++, поэтому unsigned
переменная выглядит немного пугающей для меня, и я знаю, что unsigned
переменные могут быть опасными, если их не использовать правильно, так - это правильно?
.size()
не относится к типуunsigned
акаunsigned int
. Это типаstd::size_t
.std::size_t
- это определение типа, определяемое _implementation. Смотрите стандарт.std::size_t
может быть эквивалентноunsigned
в вашей текущей реализации, но это не имеет значения. Притворство может привести к непереносимому коду и неопределенному поведению.std::size_t
на практике. Как вы думаете, мы уже охватили все это в этом бессвязном потоке комментариев за 6 лет?Ответы:
Для повторения в обратном направлении смотрите этот ответ .
Итерация вперед почти идентична. Просто измените итераторы / своп декремент на приращение. Вы должны предпочесть итераторы. Некоторые люди советуют вам использовать
std::size_t
в качестве типа переменной индекса. Однако это не переносимо. Всегда используйтеsize_type
typedef контейнера (хотя в случае прямой итерации вы можете избежать только преобразования в действительности, в действительностиstd::size_t
, в случае обратной итерации он может пойти не так, как надо , еслиstd::size_t
он шире, чем typedefsize_type
) :Использование std :: vector
Использование итераторов
Важно то, что всегда используйте форму приращения префикса для итераторов, определения которых вы не знаете. Это гарантирует, что ваш код работает как можно более универсальным.
Использование диапазона C ++ 11
Использование индексов
Использование массивов
Использование итераторов
Использование диапазона C ++ 11
Использование индексов
Прочитайте в обратной итерации ответ, к какой проблеме
sizeof
может привести подход.источник
for (auto p : polygon){sum += p;}
Прошло четыре года, Google дал мне этот ответ. Со стандартом C ++ 11 (он же C ++ 0x ) на самом деле есть новый приятный способ сделать это (ценой нарушения обратной совместимости): новое
auto
ключевое слово. Это избавляет вас от необходимости явно указывать тип используемого итератора (повторяя векторный тип), когда очевидно (для компилятора), какой тип использовать. Сv
быть вашимvector
, вы можете сделать что - то вроде этого:C ++ 11 идет еще дальше и дает вам специальный синтаксис для перебора коллекций, таких как векторы. Это устраняет необходимость писать вещи, которые всегда одинаковы:
Чтобы увидеть это в работающей программе, создайте файл
auto.cpp
:На момент написания этой статьи, когда вы компилируете это с помощью g ++ , вам обычно нужно настроить его на работу с новым стандартом, задав дополнительный флаг:
Теперь вы можете запустить пример:
Обратите внимание, что инструкции по компиляции и запуску относятся к компилятору gnu c ++ в Linux , программа должна быть независимой от платформы (и компилятора).
источник
for (auto& val: vec)
std::vector<int> v = std::vector<int>();
, или вы могли бы просто использоватьstd::vector<int> v;
вместо этого?В конкретном случае в вашем примере я бы использовал алгоритмы STL для достижения этой цели.
Для более общего, но все же довольно простого случая, я бы пошел с:
источник
Относительно ответа Йоханнеса Шауба:
Это может работать с некоторыми компиляторами, но не с gcc. Проблема здесь заключается в том, является ли std :: vector :: iterator типом, переменной (членом) или функцией (методом). Мы получаем следующую ошибку с gcc:
Решение использует ключевое слово typename, как сказано:
источник
T
это аргумент шаблона, и, следовательно, выражениеstd::vector<T*>::iterator
является зависимым именем. Для того чтобы зависимое имя было проанализировано как тип, ему должно предшествоватьtypename
ключевое слово, как указывает диагностика.Вызов
vector<T>::size()
возвращает значение типаstd::vector<T>::size_type
, а не int, unsigned int или иным образом.Также обычно итерация над контейнером в C ++ выполняется с использованием итераторов , как это.
Где T - это тип данных, которые вы храните в векторе.
Или , используя различные алгоритмы итерации (
std::transform
,std::copy
,std::fill
,std::for_each
и т.д.).источник
Используйте
size_t
:Цитируя Википедию :
источник
#include <cstddef>
а не<stddef.h>
или, что еще хуже, полностью[c]stdlib
использовать и использовать,std::size_t
а не неквалифицированную версию - и то же самое для любой другой ситуации, когда у вас есть выбор между<cheader>
и<header.h>
.Немного истории:
Чтобы определить, является ли число отрицательным или нет, используйте бит знака.
int
тип данных со знаком, означающий, что он может содержать положительные и отрицательные значения (от -2 млрд до 2 млрд).Unsigned
может хранить только положительные числа (и поскольку он не тратит немного времени на метаданные, он может хранить больше: от 0 до около 4 миллиардов).std::vector::size()
возвращаетunsigned
, а как вектор может иметь отрицательную длину?Предупреждение говорит вам, что правый операнд вашего оператора неравенства может содержать больше данных, чем левый.
По сути, если у вас есть вектор с более чем 2 миллиардами записей и вы используете целое число для индексации, вы столкнетесь с проблемами переполнения (int вернется к отрицательным 2 миллиардам).
источник
Я обычно использую BOOST_FOREACH:
Работает с контейнерами STL, массивами, строками в стиле C и т. Д.
источник
Чтобы быть полным, синтаксис C ++ 11 включает только одну версию для итераторов ( ссылка ):
Что также удобно для обратной итерации
источник
В С ++ 11
Я бы использовал общие алгоритмы, например,
for_each
чтобы избежать поиска правильного типа итератора и лямбда-выражения, чтобы избежать дополнительных именованных функций / объектов.Короткий «симпатичный» пример для вашего конкретного случая (предполагается, что многоугольник - это вектор целых чисел):
проверено на: http://ideone.com/i6Ethd
Не забудьте включить: алгоритм и, конечно же, вектор :)
На самом деле у Microsoft есть хороший пример этого:
источник: http://msdn.microsoft.com/en-us/library/dd293608.aspx
источник
источник
Первый тип правильный и правильный в некотором смысле. (Если вы думаете о том, что размер никогда не может быть меньше нуля.) Однако это предупреждение кажется мне одним из хороших кандидатов на игнорирование.
источник
i == INT_MAX
, тоi++
вызывает неопределенное поведение. В этот момент все может случиться.Подумайте, нужно ли вообще повторять
<algorithm>
Стандартный заголовок дает нам средства для этого:Другие функции в библиотеке алгоритмов выполняют общие задачи - убедитесь, что вы знаете, что доступно, если хотите сэкономить силы.
источник
Непонятная, но важная деталь: если вы скажете «for (auto it)» следующим образом, вы получите копию объекта, а не фактический элемент:
Чтобы изменить элементы вектора, вам нужно определить итератор как ссылку:
источник
Если ваш компилятор поддерживает это, вы можете использовать диапазон для доступа к элементам вектора:
Отпечатки: 1 2 3. Обратите внимание, что вы не можете использовать эту технику для изменения элементов вектора.
источник
Два сегмента кода работают одинаково. Тем не менее, unsigned int "маршрут верен. Использование типов unsigned int будет лучше работать с вектором в экземпляре, в котором вы его использовали. Вызов функции-члена size () для вектора возвращает целочисленное значение без знака, поэтому вы хотите сравнить переменную «я» к значению своего собственного типа.
Кроме того, если вы все еще немного обеспокоены тем, как «unsigned int» выглядит в вашем коде, попробуйте «uint». Это в основном сокращенная версия «unsigned int», и она работает точно так же. Вам также не нужно включать другие заголовки, чтобы использовать его.
источник
Добавляя это, поскольку я не мог найти это упомянутое в любом ответе: для основанной на индексе итерации мы можем использовать,
decltype(vec_name.size())
который оценил бы кstd::vector<T>::size_type
пример
источник