Чтение онлайн

на главную - закладки

Жанры

Эффективное использование STL
Шрифт:

Рассмотрим несколько сигнатур

insert
и
erase
в контейнере
vector<T>
:

iterator insert(iterator position, const T& x);

iterator erase(iterator position);

iterator erase(iterator rangeBegin, iterator rangeEnd);

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

iterator
. Не
const_iterator
, не
reverse_iterator
и не
const_reverse_iterator
только
iterator
. Хотя контейнеры поддерживают четыре типа итераторов, один из этих типов обладает привилегиями, отсутствующими у других типов. Тип
iterator
занимает особое место.

На следующей диаграмме показаны преобразования, возможные между итераторами разных типов.

Из рисунка следует, что

iterator
преобразуется в
const_iterator
и
reverse_iterator
, а
reverse_iterator
— в
const_reverse_iterator
. Кроме того,
reverse_iterator
преобразуется в
iterator
при помощи функции
base
типа
reverse_iterator
, а
const_reverse_iterator
аналогичным образом преобразуется в
const_iterator
. Однако из рисунка не видно, что итераторы, полученные при вызове
base
, могут оказаться не теми, которые вам нужны. За подробностями обращайтесь к совету 28.

Обратите внимание: не существует пути от

const_iterator
к
iterator
или от
const_reverse_iterator
к
reverse_iterator
. Из этого важного обстоятельства следует, что
const_iterator
и
const_reverse_iterator
могут вызвать затруднения с некоторыми функциями контейнеров. Таким функциям необходим тип
iterator
, а из-за отсутствия обратного перехода от
const
– итераторов к
iterator
первые становятся в целом бесполезными, если вы хотите использовать их для определения позиции вставки или удаления элементов.

Однако не стоит поспешно заключать, что

const
итераторы вообще бесполезны. Это не так. Они прекрасно работают с алгоритмами, поскольку для алгоритмов обычно подходят все типы итераторов, относящиеся к нужной категории. Кроме того,
const
– итераторы подходят для многих функций контейнеров. Проблемы возникают лишь с некоторыми формами
insert
и
erase
.

Обратите внимание на формулировку:

const
– итераторы становятся в целом бесполезными, если вы хотите использовать их для определения позиции вставки или удаления элементов. Называть их полностью бесполезными было бы неправильно. Const-итераторы могут принести пользу, если вы найдете способ получения
iterator
для
const_iterator
или
const_reverse_iterator
. Такое возможно часто, но далеко не всегда, причем даже в благоприятном случае решение не очевидно, да и эффективным его не назовешь. В двух словах этот вопрос не изложить, если вас заинтересуют подробности — обращайтесь к совету 27. А пока имеющаяся информация позволяет понять, почему типу
iterator
отдается предпочтение перед его
const
– и
reverse
– аналогами.

• Некоторым версиям

insert
и
erase
при вызове должен передаваться тип
iterator
.
Const
– и
reverse
– итераторы им не подходят.

• Автоматическое преобразование

const
– итератора в
iterator
невозможно, а методика получения
iterator
на основании
const_iterator
(совет 27) применима не всегда, да и эффективность ее не гарантируется.

• Преобразование

reverse_iterator
в
iterator
может требовать дополнительной регулировки итератора. В совете 28 рассказано, когда и почему возникает такая необходимость.

Из сказанного следует однозначный вывод: если вы хотите работать с контейнерами просто и эффективно и по возможности застраховаться от нетривиальных ошибок, выбирайте

iterator
вместо его
const
– и
reverse
– аналогов.

На практике выбирать обычно приходится между

iterator
и
const_iterator
. Выбор между
iterator
и
reverse_iterator
часто происходит помимо вашей воли — все зависит от того, в каком порядке должны перебираться элементы контейнера (в прямом или в обратном). А если после выбора
reverse_iterator
потребуется вызвать функцию контейнера, требующую
iterator
, вызовите функцию
base
(возможно, с предварительной регулировкой смещения — см. совет 28).

При выборе между

iterator
и
const_iterator
рекомендуется выбирать
iterator
даже в том случае, если можно обойтись
const_iterator
, а использование
iterator
не обусловлено необходимостью вызова функции контейнера. В частности, немало хлопот возникает при сравнениях
iterator
с
const_iterator
. Думаю, вы согласитесь, что следующий фрагмент выглядит вполне логично:

typedef deque<int> IntDeque; // Определения типов

typedef IntDeque:iterator Iter; // упрощают работу

typedef IntDeque::const_iterator ConstIter; // с контейнерами STL

// и типами итераторов

iter i;

ConstIter ci;

… // i и ci указывают на элементы

// одного контейнера

if (i==ci)… // Сравнить iterator

//c const_iterator

В данном примере происходит обычное сравнение двух итераторов контейнера, подобные сравнения совершаются в STL сплошь и рядом. Просто один объект относится к типу

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

Именно это и происходит в хорошо спроектированных реализациях STL, но в некоторых случаях приведенный фрагмент не компилируется. Причина заключается в том, что такие реализации объявляют

operator==
функцией класса
const_iterator
вместо внешней функции. Впрочем, вас, вероятно, больше интересуют не корни проблемы, а ее решение, которое заключается в простом изменении порядка итераторов:

if (c==i)… // Обходное решение для тех случаев,

// когда приведенное выше сравнение не работает

Подобные проблемы возникают не только при сравнении, но и вообще при смешанном использовании

iterator
и
const_iterator
(или
reverse_iterator
и
const_reverse_iterator
) в одном выражении, например, при попытке вычесть один итератор произвольного доступа из другого:

if (i-ci>=3)… // Если i находится минимум в трех позициях после ci…

Поделиться:
Популярные книги

Неудержимый. Книга XVIII

Боярский Андрей
18. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XVIII

Защитник

Кораблев Родион
11. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Защитник

Ратник

Ланцов Михаил Алексеевич
3. Помещик
Фантастика:
альтернативная история
7.11
рейтинг книги
Ратник

Последняя жена Синей Бороды

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Последняя жена Синей Бороды

Дракон с подарком

Суббота Светлана
3. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
6.62
рейтинг книги
Дракон с подарком

Огненный князь 4

Машуков Тимур
4. Багряный восход
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Огненный князь 4

Диверсант

Вайс Александр
2. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
Диверсант

Вперед в прошлое 6

Ратманов Денис
6. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 6

Жена по ошибке

Ардова Алиса
Любовные романы:
любовно-фантастические романы
7.71
рейтинг книги
Жена по ошибке

На границе империй. Том 7. Часть 3

INDIGO
9. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.40
рейтинг книги
На границе империй. Том 7. Часть 3

Дайте поспать!

Матисов Павел
1. Вечный Сон
Фантастика:
юмористическое фэнтези
постапокалипсис
рпг
5.00
рейтинг книги
Дайте поспать!

Медиум

Злобин Михаил
1. О чем молчат могилы
Фантастика:
фэнтези
7.90
рейтинг книги
Медиум

Черный Маг Императора 5

Герда Александр
5. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 5

Я не Монте-Кристо

Тоцка Тала
Любовные романы:
современные любовные романы
5.57
рейтинг книги
Я не Монте-Кристо