C ++ STL Векторы: Получить итератор из индекса?


201

Итак, я написал кучу кода, который обращается к элементам вектора stl по индексу [], но теперь мне нужно скопировать только часть вектора. Похоже, vector.insert(pos, first, last)это функция, которую я хочу ... за исключением того, что у меня есть только первый и последний как целые. Есть ли хороший способ получить итератор для этих значений?



Если я не ошибаюсь, ни один из ответов не делает никаких проверок границ, что может быть проблемой. В частности, документы std :: advance говорят, что поведение не определено, если вы используете его для преодоления границ нижележащего контейнера.
Мартин

Ответы:


293

Попробуй это:

vector<Type>::iterator nth = v.begin() + index;

4
Как правило, вы можете использовать ту же арифметику с итераторами STL, чем с указателями. Они предназначены для обмена при использовании алгоритмов STL.
Винсент Роберт

18
@VincentRobert: наоборот. Указатели являются допустимыми реализациями случайных итераторов STL, самой мощной категории. Но другие, менее мощные категории, такие как прямые итераторы, не поддерживают ту же арифметику.
MSalters

6
Я хотел бы не добавлять свои пять центов к этому ответу и рекомендоватьstd::next(v.begin(), index)
stryku

88

способ упомянутый @dirkgently ( v.begin() + index )хорош и быстр для векторов

но самый общий способ и для итераторов с произвольным доступом тоже работает постоянное время. std::advance( v.begin(), index )

РЕДАКТИРОВАТЬ
различия в использовании:

std::vector<>::iterator it = ( v.begin() + index );

или

std::vector<>::iterator it = v.begin();
std::advance( it, index );

добавлено после @litb заметок.


разве std :: advance не требует неконстантного итератора в качестве первого аргумента?
goldPseudo

Вы можете использовать std :: advance с постоянными и неконстантными итераторами
bayda

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

1
Я думаю, что проблема заключается в путанице по поводу значения «const»: advance () с удовольствием будет работать с const_iterator <T>, который является изменяемым итератором, который ссылается на элемент const типа T; он не будет работать с объектом итератора, который сам является const (то есть «const iterator <T>» или «iterator <T> const»).
j_random_hacker

7
Если вы знаете, что имеете дело с std::vector, нет смысла использовать std::advance. Это только заманивает вас к мысли, что вы пишете независимый от контейнера код (чего вы не делаете, думая о правилах аннулирования итераторов, различных сложностях во время выполнения и еще чего-то). Единственный случай, когда это std::advanceимеет смысл, - это когда вы сами пишете шаблон, который не знает, с каким итератором он работает.
Фрерих Раабе

47

Также; auto it = std::next(v.begin(), index);

Обновление: необходим компилятор, совместимый с C ++ 11x


2
Следует отметить, что это путь C ++ 11! std :: next эквивалентно std :: advance. Использование этих функций вместо использования арифметики значительно упрощает обмен типами контейнеров. Даже работает на c-массивах afaik, точно так же, как std :: begin и std :: end.
Zoomulator

2
Также следует отметить, что std :: advance разработан идиотом, так как в качестве вывода используется ссылка, а не возвращаемое значение.
Виктор Сехр

1
for (auto it = begin (c); it! = end (c); advance (it, n)) {...}
Zoomulator

2
Оба имеют свое применение. stda :: advance полезна для изменения итератора на месте. Это проблема производительности в циклах. Я бы предпочел следующий в случае назначения, как вы предлагаете. Я только нашел это немного резким, утверждая, что это идиотизм. Обе функции были разработаны с учетом различных ситуаций, хотя они в основном одинаковы.
Zoomulator

5
@Zoomulator: если копирование вашего итератора вызывает проблемы с производительностью, у вас есть более серьезные проблемы.
Mooing Duck


-3

На самом деле std :: vector предназначены для использования в качестве вкладки C при необходимости. (Стандарт C ++ требует, чтобы для векторной реализации, насколько я знаю, замена для массива в Википедии ) Например, совершенно законно сделать следующее, по моему мнению:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

Конечно, либо foo не должен копировать адрес, переданный в качестве параметра, и сохранять его где-либо, либо вы должны убедиться в том, что в вашей программе никогда не добавляется какой-либо новый элемент в vec или не запрашивается изменение его емкости. Или ошибка сегментации риска ...

Поэтому в вашем примере это приводит к

vector.insert(pos, &vec[first_index], &vec[last_index]);

Меня удивляет, почему они решили абстрагироваться от итераторов, если они просто указатели ... они по сути "скрывают" эти возможности.
mpen

Для удобства? Как это позволит вам легко удалить экземпляр вектора для любого другого типа контейнера в вашем коде.
Ив Бомес

4
& vec [i] возвращает указатель, который не обязательно совместим с vector <> :: iterator. Преимущество vec.begin () + i заключается в том, что итератор, определяемый вашей библиотекой, по-прежнему имеет значение, включая проверенные итераторы в режиме отладки, например. Поэтому, если вам не нужен указатель (например, для ввода / вывода), вы всегда должны предпочитать итераторы.
Sellibitze

@KerrekSB Начиная с 23.3.6.1 в стандартном черновике c ++: «Элементы вектора хранятся непрерывно, что означает, что если v - это вектор <T, Allocator>, где T - некоторый тип, отличный от bool, то он подчиняется тождеству & v [ n] == & v [0] + n для всех 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes: это не имеет ничего общего с векторными итераторами. Однако это правда, что голые указатели также являются итераторами - они просто не являются векторными итераторами.
Керрек С.Б.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.