Перейти к содержимому

Как получить итератор на элемент vector

  • автор:

Как получить итератор на элемент vector

Итераторы обеспечивают доступ к элементам контейнера и представляют реализацию распространенного паттерна объектно-ориентированного программирования «Iterator». С помощью итераторов очень удобно перебирать элементы. В C++ итераторы реализуют общий интерфейс для различных типов контейнеров, что позволяет использовать единой подход для обращения к элементам разных типов контейнеров.

Стоит отметить, что итераторы имеют только контейнеры, адаптеры контейнеров — типы std::stack , std::queue и std::priority_queue итераторов не имеют.

Итератор описывается типом iterator . Для каждого контейнера конкретный тип итератора будет отличаться. Так, итератор для контейнера list представляет тип list::iterator , а итератор контейнера vector представляет тип vector::iterator и так далее. Однако общий функционад, который применяется для доступа к элементам, будет аналогичен.

Для получения итераторов контейнеры в C++ обладают такими функциями, как begin() и end() . Функция begin() возвращает итератор, который указывает на первый элемент контейнера (при наличии в контейнере элементов). Функция end() возвращает итератор, который указывает на следующую позицию после последнего элемента, то есть по сути на конец контейнера. Если контейнер пуст, то итераторы, возвращаемые обоими методами begin и end совпадают. Если итератор begin не равен итератору end, то между ними есть как минимум один элемент.

Обе этих функции возвращают итератор для конкретного типа контейнера:

#include #include int main() < std::vectornumbers< 1,2,3,4 >; std::vector::iterator iter = numbers.begin(); // получаем итератор >

В данном случае создается вектор — контейнер типа vector, который содержит значения типа int. И этот контейнер инициализируется набором . И через метод begin() можно получить итератор для этого контейнера. Причем этот итератор будет указывать на первый элемент контейнера.

С итераторами можно проводить следующие операции:

  • *iter : получение элемента, на который указывает итератор
  • ++iter : перемещение итератора вперед для обращения к следующему элементу
  • —iter : перемещение итератора назад для обращения к предыдущему элементу. Итераторы контейнера forward_list не поддерживают операцию декремента.
  • iter1 == iter2 : два итератора равны, если они указывают на один и тот же элемент
  • iter1 != iter2 : два итератора не равны, если они указывают на разные элементы
  • iter + n : возвращает итератор, который смещен от итератора iter на n позиций вперед
  • iter — n : возвращает итератор, который смещен от итератора iter на n позиций назад
  • iter += n : перемещает итератор на n позиций вперед
  • iter -= n : перемещает итератор на n позиций назад
  • iter1 — iter2 : возвращает количество позиций между итераторами iter1 и iter2
  • >, >=,

Стоит отметить, что итераторы не всех контейнеров поддерживают все эти операции.

Итераторы для типов std::forward_list , std::unordered_set и std::unordered_map не поддерживают операции —, -= и -. (поскольку std::forward_list — однонаправленный список, где каждый элемент хранит указатель только на следующий элемент)

Итераторы для типа std::list поддерживают операции инкремента и декремента, но не поддерживаются операции +=, -=, + и -. Те же ограничения имеют итераторы контейнеров std::map и std::set .

Операции +=, -=, +, -, , >= и поддерживаются только итераторами произвольного доступа (итераторы контейнеров std::vector , array и deque )

Получение и изменение элемента контейнера

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

#include #include int main() < std::vectornumbers< 1,2,3,4 >; auto iter < numbers.begin() >; // получаем итератор // получаем элемент, на который указывает итератор std::cout 

После получения итератора он будет указывать на первый элемент контейнера. То есть при выражение *iter возвратит первый элемент вектора.

Прибавляя или отнимая определенное число, можно переместить итератор вперед или назад на определенное количество элементов:

#include #include int main() < std::vectornumbers< 10, 20, 30, 40 >; auto iter < numbers.begin() >; // получаем итератор // переходим на 1 элемент вперед ко 2-му элементу ++iter; std::cout 

Опять же повторю, что стоит учитывать, что не все операции поддерживаются итераторами всех контейнеров.

Перебор контейнера

Например, используем итераторы для перебора элементов вектора:

#include #include int main() < std::vectornumbers< 10, 20, 30, 40 >; auto iter < numbers.begin() >; // получаем итератор while(iter!=numbers.end()) // пока не дойдем до конца < std::cout // аналогичный пример с циклом for for(auto start; start !=numbers.end(); start++ ) < std::cout >

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

Константные итераторы

Если контейнер представляет константу, то для обращения к элементам этого контейнера можно использовать только константный итератор (тип const_iterator ). Такой итератор позволяет считывать элементы, но не изменять их:

const vector numbers; for(auto iter ; iter != numbers.end(); ++iter) < std::cout 

В данном случае итератор iter будет представлять тип std::vector::const_iterator .

Для получения константного итератора также можно использовать функции cbegin() и cend . При этом даже если контейнер не представляет константу, но для его перебора используется константный итератор, то опять же нельзя изменять значения элементов этого контейнера:

#include #include int main() < std::vectornumbers < 1, 2, 3, 4, 5 >; for (auto iter ; iter != numbers.cend(); ++iter) < std::cout >

Стоит отметить, что для типов std::set (множество) и std::map (словарь) доступны только константные итераторы.

Реверсивные итераторы

Реверсивные итераторы позволяют перебирать элементы контейнера в обратном направлении. Для получения реверсивного итератора применяются функции rbegin() и rend() , а сам итератор представляет тип reverse_iterator :

#include #include int main() < std::vectornumbers < 1, 2, 3, 4, 5 >; for (auto iter ; iter != numbers.rend(); ++iter) < std::cout std::cout

В данном случае итератор будет представлять тип std::vector::reverse_iterator . Консольный вывод программы:

5 4 3 2 1

Если надо обеспечить защиту от изменения значений контейнера, то можно использовать константный реверсивный итератор, который представлен типом const_reverse_iterator и который можно получить с помощью функций crbegin() и crend() :

#include #include int main() < std::vectornumbers < 1, 2, 3, 4, 5 >; for (auto iter ; iter != numbers.crend(); ++iter) < std::cout >

Итераторы для массивов

Для массивов в C++ также имеется поддержка итераторов. Для этого в стандартной библиотеке С++ определены функции std::begin() (возвращает итератор на начало массива) и std::end() (возвращает итератор на конец массива):

int data[]; // получаем итератор на начало массива auto iter = std::begin(data); // получаем итератор на конец массива auto end = std::end(data);

Как и контейнеры, массив можно перебрать с помощью итераторов:

#include int main() < int data[]; // перебор массива с помощью итераторов for(auto iter ; iter != std::end(data); iter++) < std::cout >

Но перебор массива вполне можно сделать и другими способами - через индексы, обычные указатели. Но итераторы на массивы могут быть полезны при манипуляции с контейнерами. Например, функция insert() , которая есть у ряда контейнеров, позволяет добавить в контейнер какую-то часть другого контейнера. Для выделения добавляемой части могут применяться итераторы. И таким образом, с помощью итераторов можно добавить в контейнер, например, в вектор какую-то часть контейнера:

#include #include int main() < int data[]; std::vector numbers < 1, 2, 3, 4>; // добавляем в конец вектора numbers из массива data элементы со 2-го по предпоследний (включительно) numbers.insert(numbers.end(), std::begin(data) + 1, std::end(data)-1); for (auto iter ; iter != numbers.end(); ++iter) < std::cout std::cout

numbers.insert(numbers.end(), std::begin(data) + 1, std::end(data)-1);

Добавляет в вектор numbers, начиная с позиции, на которую указывает итератор numbers.end() (то есть в самый конец вектора), диапазон элементов массива data. Начало этого диапазона задается выражением std::begin(data) + 1 (то есть со 2-го элемента), а конуц — выражением std::end(data)-1 (то есть по предпоследний элемент включительно). Консольный вывод:

stl: добавить в вектор элемент и получить его итератор

Подскажите, можно ли добавить в вектор элемент и получить итератор одной функцией или все таки придется делать так:

data.push_back(object); auto it = data.begin() + (data.size() - 1); 

Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 16 янв 2019 в 10:28
37.1k 4 4 золотых знака 26 26 серебряных знаков 69 69 бронзовых знаков

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

auto it; 

Отслеживать
ответ дан 16 янв 2019 в 11:07
user7860670 user7860670
29.6k 3 3 золотых знака 17 17 серебряных знаков 36 36 бронзовых знаков

Вопрос был о добавлении существующего объекта object , функция emplace тут подходит слабо так как требует лишнего копирования объекта.

16 янв 2019 в 12:07

@freim Что значит «не подходит»? Это рабочий код. Никакого лишнего копирования или создания ненужных промежуточных объектов тут не происходит (в отличие от функции insert ).

16 янв 2019 в 12:13
а чем emplace от Insert в конец отличается?
16 янв 2019 в 12:24

В данном случае emplace будет полностью эквивалентно insert — и там, и там будет вызываться конструктор копии. Работать, конечно, будет, но это нецелевое и вводящее в заблуждение использование функции. К тому же в случае insert можно использовать и перемещение — в отличие от emplace .

16 янв 2019 в 12:56

@freim: Что за ерунда? Функции emplace почти полностью замещают функции push и insert . В современнои коде надо стараться пользоваться именно emplace . Ничего нецелевого здесь нет — наоборот, именно так и надо. И emplace по определению полностью поддерживает перемещение. О каком «в отличие» вы ведете речь?

Как получить итератор на элемент vector

По ходу туплю товарищи.

Есть вектор vec1, заполненый некоторыми данными, и есть индекс элемента.
То есть, что бы получить данные из первого вектора нужно выполнить что-то наподобие:

vec1[Index];

Требуется получить итератор на элемент вектора, то есть, что-то вроде:

vector vec1; vector ::iterator itData; . itData = GetItByIndex(Index);

Вопрос — как ?
Или я что-то упустил.

Re: Получить итератор элемента vector по индексу ?

От: Venn
Дата: 13.02.06 12:10
Оценка:

On Mon, 13 Feb 2006 14:08:31 +0200, wrote:

> [ccode]vector vec1;
> vector ::iterator itData;
> .

Posted via RSDN NNTP Server 1.9
Re: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 12:11
Оценка:
vector vec1; vector ::iterator itData; . itData = vec1.begin()+Index; itData = std::advance( begin(), Index );

Re: Получить итератор элемента vector по индексу ?

От: ekamaloff
Дата: 13.02.06 12:11
Оценка:

Здравствуйте, Аноним, Вы писали:

А>Требуется получить итератор на элемент вектора, то есть, что-то вроде:

vector ::iterator itData = vec1.begin() + Index;

It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Re[2]: Получить итератор элемента vector по индексу ?

От: ekamaloff
Дата: 13.02.06 12:13
Оценка:

Здравствуйте, srggal, Вы писали:

S>Здравствуйте, , Вы писали:

S>

S>itData = std::advance( begin(), Index ); S>
itData = vec1.begin(); std::advance( itData, Index );

It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Re[2]: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 12:15
Оценка:

Здравствуйте, Venn, Вы писали:

V>On Mon, 13 Feb 2006 14:08:31 +0200, wrote:

>> [ccode]vector vec1;
>> vector ::iterator itData;
>> .

V>itData += Index;

itData — в примере АТ — неинициализирован.

Re[3]: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 12:16
Оценка:

Здравствуйте, ekamaloff, Вы писали:

E>Скорее так:

E>

E>itData = vec1.begin(); E>std::advance( itData, Index ); E>

Конечно именно так.

Re: Получить итератор элемента vector по индексу ?

От: Dmitry Kotlyarov
Дата: 13.02.06 12:30
Оценка: -3

Здравствуйте, Аноним, Вы писали:

А>Требуется получить итератор на элемент вектора, то есть, что-то вроде:

А>

vector vec1; А>vector ::iterator itData; А>. А>itData = GetItByIndex(Index);

Re[3]: Получить итератор элемента vector по индексу ?

От: sadomovalex http://sadomovalex.blogspot.com
Дата: 13.02.06 12:59
Оценка:

Здравствуйте, ekamaloff, Вы писали:

E>Здравствуйте, srggal, Вы писали:

S>>Здравствуйте, , Вы писали:

S>>

S>>itData = std::advance( begin(), Index ); S>>

E>Скорее так:

E>

E>itData = vec1.begin(); E>std::advance( itData, Index ); E>

а какая разница? временный объект будет жив до конца полного выражения, в котором он используется, так что ссылка на него будет валидной до выхода из advance

«Что не завершено, не сделано вовсе» Гаусс
Re[3]: Получить итератор элемента vector по индексу ?

От: Venn
Дата: 13.02.06 13:04
Оценка:

> itData — в примере АТ — неинициализирован.

главное — идею он понял

Posted via RSDN NNTP Server 1.9
Re[4]: Получить итератор элемента vector по индексу ?

От: ekamaloff
Дата: 13.02.06 13:05
Оценка:

Здравствуйте, sadomovalex, Вы писали:

E>>

E>>itData = vec1.begin(); E>>std::advance( itData, Index ); E>>

S>а какая разница? временный объект будет жив до конца полного выражения, в котором он используется, так что ссылка на него будет валидной до выхода из advance

Тут дело немного в другом:

templateclass InputIterator, class Distance> void advance( InputIterator& _InIt, Distance _Off );

Первый параметр — итератор, который следует инкрементировать. Возвращаемое значение — void. Делаем выводы.

It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Re[4]: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 13:06
Оценка:

Здравствуйте, sadomovalex, Вы писали:

S>а какая разница? временный объект будет жив до конца полного выражения, в котором он используется, так что ссылка на него будет валидной до выхода из advance

Не скомпилится мой вариант, Ибо некорректен.

 templateclass InputIterator, class Distance> void advance( InputIterator& _InIt, Distance _Off );

Re[5]: Получить итератор элемента vector по индексу ?

От: sadomovalex http://sadomovalex.blogspot.com
Дата: 13.02.06 13:17
Оценка:

Здравствуйте, ekamaloff, Вы писали:

E>Здравствуйте, sadomovalex, Вы писали:

E>>>

E>>>itData = vec1.begin(); E>>>std::advance( itData, Index ); E>>>

S>>а какая разница? временный объект будет жив до конца полного выражения, в котором он используется, так что ссылка на него будет валидной до выхода из advance

E>Тут дело немного в другом:

E>

E>templateclass InputIterator, class Distance> E> void advance( E> InputIterator& _InIt, E> Distance _Off E> ); E>

E>Первый параметр — итератор, который следует инкрементировать. Возвращаемое значение — void. Делаем выводы.

«Что не завершено, не сделано вовсе» Гаусс
Re[6]: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 13:25
Оценка:

Здравствуйте, sadomovalex, Вы писали:

Юзал advance и не задумывался, а почему он не возвращает ссылку на итератор, а вот ошибся, и задумался, рационального ответа так и не нашел, все только на уровне — «Исторически так сложилось».

Re[7]: Получить итератор элемента vector по индексу ?

От: sadomovalex http://sadomovalex.blogspot.com
Дата: 13.02.06 13:46
Оценка:

Здравствуйте, srggal, Вы писали:

S>Здравствуйте, sadomovalex, Вы писали:

S>Юзал advance и не задумывался, а почему он не возвращает ссылку на итератор, а вот ошибся, и задумался, рационального ответа так и не нашел, все только на уровне — «Исторически так сложилось».

наверное для того, чтобы не создавать дополнительных временных объектов

«Что не завершено, не сделано вовсе» Гаусс
Re[8]: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 13:49
Оценка:

Здравствуйте, sadomovalex, Вы писали:

S>наверное для того, чтобы не создавать дополнительных временных объектов

Я грил о возврате аргумента (по ссылке) первого аргумент.

Re[9]: Получить итератор элемента vector по индексу ?

От: sadomovalex http://sadomovalex.blogspot.com
Дата: 13.02.06 13:58
Оценка:

Здравствуйте, srggal, Вы писали:

S>Здравствуйте, sadomovalex, Вы писали:

S>>наверное для того, чтобы не создавать дополнительных временных объектов

S>Я грил о возврате аргумента (по ссылке) первого аргумент.

т.е. просто добавить в advance return ?

«Что не завершено, не сделано вовсе» Гаусс
Re[10]: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 14:04
Оценка:

Здравствуйте, sadomovalex, Вы писали:

S>т.е. просто добавить в advance return ?

Да, именно об этом я и грю.

Re[11]: Получить итератор элемента vector по индексу ?

От: kan_izh
Дата: 13.02.06 14:40
Оценка:

srggal wrote:

> S>т.е. просто добавить в advance return ?
> Да, именно об этом я и грю.
Видимо, чтобы избежать след. граблей:
const_iterator current = . ;
const_iterator next = advance(current, 1);

Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[12]: Получить итератор элемента vector по индексу ?

От: srggal
Дата: 13.02.06 14:50
Оценка:

Здравствуйте, kan_izh, Вы писали:

Для меня это не рациональный ответ, ибо такая «забота» о пользователях итераторов никоим образом не согласуется с тем, что во многих случаях пользователь итераторов должен быть внимателен дабы не насиупить на грабли:
— *end();
— std::find( cont1.begin(), cont2.end() );
— etc.

const_iterator current = cont.begin(); const_iterator next; std::advance(next, 0); if(*current != *next)

ЗЫ и Ваш и мой пример притянуты за очень длинные уши

Как получить итератор вектора с типом структуры в шаблоннном классе?

Есть класса А.
Внутри него есть структура, которая содержит поле с шаблонным типом.
В функции f() мне нужно к примеру получить итератор (в моем случае для поиска).
Но почему я не могу объявить итератор?
Получается в таком виде я вообще не могу работать с итераторами?

template class A < public: A(); ~A(); void f(void* o); typedef struct < T* t; int i; >t_t; std::vector v; >; template A::A() <> template A::~A() <> template void A::f(void* o) < // объявление итератора не работает // std::vector::iterator it = v.begin(); static_cast(o)->push(); >
  • Вопрос задан более трёх лет назад
  • 290 просмотров

2 комментария

Средний 2 комментария

myjcom

Roman @myjcom Куратор тега C++

hakain

Vi Vola @hakain Автор вопроса
Roman, у меня с++03
Решения вопроса 1

Nipheris

Станислав Макаров @Nipheris Куратор тега C++

typename std::vector::iterator it = v.begin();

Ответ написан более трёх лет назад
Нравится 2 4 комментария

hakain

Vi Vola @hakain Автор вопроса
работает.
Но почему?
В чем вообще смысл такого синтаксиса?

Nipheris

Станислав Макаров @Nipheris Куратор тега C++
Вот прекрасное объяснение: https://ru.stackoverflow.com/questions/239051/%D0%.

Nipheris

Станислав Макаров @Nipheris Куратор тега C++
Евгений Шатунов @MarkusD Куратор тега C++

Vi Vola , все дело в том, что внутренние имена шаблона еще не выведены на этапе вывода типа из этого шаблона. Код std::vector является конструкцией инстанциирования типа из шаблона. На данный момент еще неизвестно, какими свойствами обладает его внутреннее имя std::vector::iterator . И для того чтобы дать компилятору понять что это именно тип, следует использовать пояснительное слово typename слева от типа.

Внутренние имена шаблона вообще только по мере использования отображаются в пространство выведенных из шаблона типов.

Ответы на вопрос 0
Ваш ответ на вопрос

Войдите, чтобы написать ответ

cpp

  • C++
  • +1 ещё

В чем ошибка кода?

  • 1 подписчик
  • 10 часов назад
  • 99 просмотров

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *