Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
STL_3.doc
Скачиваний:
7
Добавлен:
01.05.2025
Размер:
132 Кб
Скачать
☆

4.13. Константные и изменяемые итераторы

Имеется еще одно дополнительное различие, применимое к однонаправленным

итераторам, двунаправленным итераторам и итераторам с произвольным доступом,— они могут быть изменяемыми (mutable) или константными (constant) в зависимости от того, является результат operator* ссылкой или константной ссылкой.

Все типы контейнеров STL определяют не только идентификатор iterator, но и const_iterator. Например, vector<T>::iterator— это изменяемый итератор с произвольным доступом, a vector<T>::const_iterator— соответствующий

константный итератор с произвольным доступом.

Когда результат применения operator* к итератору i представляет собой ссылку, можно выполнить присваивание *i = .... Такое присваивание, однако, невозможно в случае ссылки константной (как в случае, когда итератор в действительности является константным итератором). Компилятор воспринимает такие попытки присваивания как ошибки.

Прочие применения разыменования, которые могут привести к изменению объекта, на который ссылается *i, такие как передача *i в функцию вместо параметра, являющегося неконстантной ссылкой (Т&, а не const T&), также не разрешаются.

В большинстве случаев можно использовать тип iterator контейнера при объявлении итераторных переменных:

vector<int> vector1;

// ... Код для вставки значений в vector1

vector<int>::iterator i = vector1.begin(); // OK

Это вполне корректно, так как функция-член begin возвращает iterator при применении к изменяемому контейнеру (т.е. к контейнеру, не объявленному как константный). В действительности можно записать и следующее:

vector<int>::const_iterator j = vector1.begin(); // OK

поскольку имеется преобразование iterator в const_iterator.

Однако если у нас имеется константный контейнер, то с ним мы должны использовать константные итераторы:

// Инициализация vector2 100 нулями:

const vector<int> vector2(100, 0);

vector<int>::iterator i = vector2.begin(); // Неверно

Вместо этого следует использовать объявление

vector<int>::const_iterator i = vector2.begin();

В первом случае применение iterator некорректно, так как функция-член begin

возвращает const_iterator при применении к контейнеру, объявленному как const.

Преобразования от const_iterator к iterator нет, так что попытка инициализировать

переменную i значением const_iterator, возвращаемым begin, приводит при компиляции к сообщению об ошибке.

Зачастую мы не хотим непосредственно объявлять контейнер константным, поскольку обычно требуется выполнять вставку или удаление элементов после его создания. Но всякий раз, когда мы передаем контейнер в функцию посредством параметра, являющегося константной ссылкой, контейнер рассматривается как объявленный константным:

template <typename T>

void print(const vector<T>& v)

{

for (vector<T>::const_iterator i = v.begin(); i != v.end(); ++i)

cout << *i << endl;

}

Попытка использовать vector<T>::iterator в этом примере приведет при компиляции к сообщению об ошибке, так же как и попытка воспользоваться функциями-членами контейнера insert или erase.

Если у нас есть функция с параметром-итератором, то этот параметр должен быть по возможности объявлен как const_iterator:

template <typename T>

void foo(list<T>::const_iterator i,

deque<T>& d, deque<T>::iterator j)

{

if (*i > *j++)

*j = *i++;

d.insert(j, *i);

}

Здесь * используется только для чтения значения, на которое указывает i, но не для присваивания посредством этого итератора, так что объявление i как const_iterator вполне допустимо. Он может быть объявлен и как iterator, но тогда соответствующий фактический параметр должен принимать только значения типа iterator. С другой стороны, переменная j должна быть объявлено как iterator, поскольку с помощью этого итератора выполняется присваивание, и он используется как параметр функции insert.

Заметим, что в этом примере и с i, и с j выполняется операция инкремента ++. Часть "const" в const_iterator не означает, что сам итератор не может изменяться— запрещается только изменение значения, на которое указывает итератор.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]