Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп читаем онлайн бесплатно полную версию! Чтобы начать читать не надо регистрации. Напомним, что читать онлайн вы можете не только на компьютере, но и на андроид (Android), iPhone и iPad. Приятного чтения!
Шрифт:
Интервал:
Закладка:
Итератор играет главную роль в определении класса list в библиотеке STL. Итераторы используются для идентификации места вставки или удаления элементов. Кроме того, их используют для “навигации” по списку вместо оператора индексирования. Такое применение итераторов очень похоже на использование указателей при перемещении по массивам и векторам, описанном в разделах 20.1 и 20.3.1. Этот вид итераторов является основным в стандартных алгоритмах (разделы 21.1–21.3).

Мы сделали тип итератора для списка членом класса (вложенным классом), потому что нет никаких причин делать его глобальным. Он используется только в списках. Кроме того, это позволяет нам называть каждый тип в контейнере именем iterator. В стандартной библиотеке есть list<T>::iterator, vector<T>::iterator, map<K,V>::iterator и т.д.
20.4.2. Итерация
Итератор списка должен обеспечивать выполнение операций *, ++, == и !=. Поскольку стандартный список является двухсвязным, в нем также есть операция –– для перемещения назад, к началу списка.
template<class Elem> class list<Elem>::iterator {
Link<Elem>* curr; // текущий узел
public:
iterator(Link* p):curr(p) { }
// вперед
iterator& operator++() {curr = curr–>succ; return *this; }
// назад
iterator& operator––() { curr = curr–>prev; return *this; }
// (разыменовать)
Elem& operator*() { return curr–>val; } // получить значение
bool operator==(const iterator& b) const
{ return curr==b.curr; }
bool operator!= (const iterator& b) const
{ return curr!=b.curr; }
};
Эти функции короткие, простые и эффективные: в них нет циклов, нет сложных выражений и подозрительных вызовов функций. Если эта реализация вам не понятна, то посмотрите на диаграммы, приведенные ранее. Этот итератор списка просто представляет собой указатель на узел с требуемыми операциями. Несмотря на то что реализация (код) для класса list<Elem>::iterator сильно отличается от обычного указателя, который использовался в качестве итератора для векторов и массивов, их семантика одинакова. По существу, итератор списка обеспечивает удобные операции ++, ––, *, ==, and != для указателя на узел.
Посмотрим на функцию high() еще раз.
template<class Iterator >
Iterator high(Iterator first, Iterator last)
// возвращает итератор на максимальный элемент в диапазоне
// [first,last)
{
Iterator high = first;
for (Iterator p = first; p!=last; ++p)
if (*high<*p) high = p;
return high;
}
Мы можем применить ее к объекту класса list.
void f()
{
list<int> lst;
int x;
while (cin >> x) lst.push_front(x);
list<int>::iterator p = high(lst.begin(), lst.end());
cout << "Максимальное значение = " << *p << endl;
}
Здесь значением аргумента класса Iterator argument является класс list<int>::iterator, а реализация операций ++, * и != совершенно отличается от массива, хотя ее смысл остается неизменным. Шаблонная функция high() по-прежнему перемещается по данным (в данном случае по объекту класса list) и находит максимальное значение. Мы можем вставлять элементы в любое место списка, так что мы использовали функцию push_front() для добавления элементов в начало списка просто для иллюстрации. С таким же успехом мы могли бы использовать функцию push_back(), как делали это для объектов класса vector.
ПОПРОБУЙТЕ
В стандартном классе vector нет функции push_front(). Почему? Реализуйте функцию push_front() для класса vector и сравните ее с функцией push_back().
Итак, настало время спросить: “А что, если объект класса list будет пустым?” Иначе говоря, “что если lst.begin()==lst.end()?” В данном случае выполнение инструкции *p будет попыткой разыменования элемента, следующего за последним, т.е. lst.end(). Это катастрофа! Или, что еще хуже, в результате можно получить случайную величину, которая исказит правильный ответ.


Существует важная причина, по которой итератор end устанавливается на элемент, следующий за последним, а не на последний элемент: пустая последовательность — не особый случай. Мы не любим особые случаи, потому что — по определению — для каждого из них приходится писать отдельный код.
В нашем примере можно поступить следующим образом:
list<int>::iterator p = high(lst.begin(), lst.end());
if (p==lst.end()) // мы достигли конца?
cout << "Список пустой";
else
cout << "максимальное значение = " << *p << endl;
Работая с алгоритмами из библиотеки STL, мы систематически используем эту проверку. Поскольку в стандартной библиотеке список предусмотрен, не будем углубляться в детали его реализации. Вместо этого кратко укажем, чем эти списки удобны (если вас интересуют детали реализации списков, выполните упр. 12–14).
20.5. Еще одно обобщение класса vector
Из примеров, приведенных в разделах 20.3 и 20.4, следует, что стандартный вектор имеет член класса, являющийся классом iterator, а также функции-члены begin() и end() (как и класс std::list). Однако мы не указали их в нашем классе vector в главе 19. Благодаря чему разные контейнеры могут использоваться более
Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.
Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.
- 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
- 2. Просьба отказаться от оскорблений, угроз и запугиваний.
- 3. Просьба отказаться от нецензурной лексики.
- 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.
Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.
Оставить комментарий
-
Гость Татьяна24 сентябрь 22:20 Как то не очень... Невеста по ошибке. Я не дам тебе развод - Майя Линн
-
Римма24 сентябрь 21:52 Почему главные героинитпкие идиотки? И сюжет не плохой, и написано хорошо. Но как героиня - так дура дурой.... Хозяйка маленького дома, или Любимая для дракона - Кира Рамис
-
Римма20 сентябрь 12:27 Много ненужных пояснений и отступлений. Весь сюжет теряет свою привлекательность. Героиня иногда так тупит, что читать не... Хозяйка приюта для перевертышей и полукровок - Елена Кутукова