Как получить итератор на элемент 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 комментария

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

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

Станислав Макаров @Nipheris Куратор тега C++
typename std::vector::iterator it = v.begin();
Ответ написан более трёх лет назад
Нравится 2 4 комментария

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

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

Станислав Макаров @Nipheris Куратор тега C++
Евгений Шатунов @MarkusD Куратор тега C++
Vi Vola , все дело в том, что внутренние имена шаблона еще не выведены на этапе вывода типа из этого шаблона. Код std::vector является конструкцией инстанциирования типа из шаблона. На данный момент еще неизвестно, какими свойствами обладает его внутреннее имя std::vector::iterator . И для того чтобы дать компилятору понять что это именно тип, следует использовать пояснительное слово typename слева от типа.
Внутренние имена шаблона вообще только по мере использования отображаются в пространство выведенных из шаблона типов.
Ответы на вопрос 0
Ваш ответ на вопрос
Войдите, чтобы написать ответ

- C++
- +1 ещё
В чем ошибка кода?
- 1 подписчик
- 10 часов назад
- 99 просмотров