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.