Вход/Регистрация
Эффективное использование STL
вернуться

Мейерс Скотт

Шрифт:

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

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…

  • Читать дальше
  • 1
  • ...
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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