Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП_ Лекция №07 - Стандартная библиотека шаблонов ч.1 .docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
296.29 Кб
Скачать

Итераторы stl-контейнеров

Получить итератор любого STL-контейнера, указывающий на начало последовательности, можно используя метод begin(), а на элемент, следующий за последним - используя метод end(). Конкретный тип каждого итератора зависит от реализации стандартной библиотеки, но доступен по стандартному синониму типа iterator:

std::vector< int > v( 10 );

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

Контейнеры также предоставляют константные итераторы - это уточнение итератора любой категории, запрещающее модификацию последовательности. Такие итераторы также получить методами begin/end (компилятор определяет какой именно вариант нужен из контекста), а стандартный синоним называется const_iterator:

std::vector< int > v( 10 );

std::vector< int >::const_iterator it = v.begin();

При помощи константных итераторов можно перебирать контейнер теми же способами, что и обычный итератор, но к данным разрешается только обращение с целью чтения. Любая попытка записи данного через константный итератор не пройдет компиляцию.

Записывать вложенные имена типов итераторов не слишком приятно, потому рекомендуется использовать ключевое слово auto для автоматического вывода типа:

std::vector< int > v( 10 );

auto it = v.begin(); // возможно обычный, возможно и константный итератор

Методы begin() и end() перегружены в вариантах с модификатором const и без него, соответственно возвращают константные или обычные итераторы. В приведенном выше примере, использующем ключевое слово auto, может быть не очевидным тип результирующего итератора - константный или обычный. В ряде случаев, могут оказаться необходимыми именно константные итераторы. В контейнерах существует пара похожих методов - cbegin() и cend(), которые всегда и при любых условиях возвращают именно константные итераторы:

std::vector< int > v( 10 );

auto it = v.сbegin(); // однозначно здесь константный итератор

Также, контейнеры предоставляют реверс-итераторы, которые инвертируют направление итерирования. Когда на таком итераторе вызывается операция ++, она транслируется в фактическую --, и наоборот. Получить такие итераторы можно вызвав методы rbegin/rend:

std::vector< int > v( 10 );

std::vector< int >::reverse_iterator rit1 = v.rbegin();

std::vector< int >::const_reverse_iterator rit2 = v.rbegin();

Если обычные итераторы begin/end можно графически представить таким образом:

то реверс-итератор начинается с последнего элемента и заканчивается элементом, условно предшествующим первому:

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

int main ()

{

std::vector< int > v;

for ( int i = 0; i < 10; i++ )

v.push_back( i );

auto it = MyFind( v.rbegin(), v.rend(), 0 );

assert( ( it.base() - v.begin() ) == 1 ) );

}

Реверс-итератор можно преобразовать в обычный итератор через метод base().

Для обеспечения целостной картины в контейнерах также существует пара методов crbegin() и crend(), которые независимо от контекста возвращают константные реверс-итераторы.

Очевиден следующий вывод - чем больше требований у алгоритма к итератору, тем меньшее число структур данных может предоставить такой итератор. Это ограничивает использование в алгоритмах. Аналогично, чем меньше требований у алгоритма к итератору, тем большее число структур данных может быть использовано вместе с этим алгоритмом.