- •2.3. Итераторы
- •2.4. Функциональные объекты
- •2.5. Адаптеры
- •2.6. Аллокаторы
- •Глава 3. Отличие stl от других библиотек
- •3.1. Расширяемость
- •3.2. Взаимозаменяемость компонентов
- •3.3. Совместимость алгоритмов и контейнеров
- •Глава 4 Итераторы
- •4.1. Входные итераторы
- •4.2. Выходные итераторы
- •4.3. Однонаправленные итераторы
- •4.4. Двунаправленные итераторы
- •4.5. Итераторы с произвольным доступом
3.1. Расширяемость
Ни одна программная библиотека не делает все, и STL — не исключение. Но по сравнению с традиционными библиотеками классов STL сравнительно легко расширить, если в этом возникнет необходимость.
В традиционных библиотеках, где алгоритмы связаны с конкретными классами, можно добавлять алгоритмы путем наследования новых классов из библиотечных. У этого подхода есть некоторые недостатки.
1. Он работает, только если проектировщик исходных классов предвидит такие расширения и предоставляет специальные средства для них (например, делает некоторые данные-члены защищенными, а не закрытыми, или некоторые функции виртуальными, а не обычными).
2. Чаще, чем этого хотелось бы, приходится прибегать к внесению изменении в исходный текст библиотеки (конечно, в предположении, что он доступен), что может привести к внесению ошибок или возникновению новых проблем при тестировании, сопровождении и управлениями версиями.
С другой стороны, STL имеет открытую и ортогональную структуру, которая позволяет программисту разработать собственные алгоритмы для работы с контейнерами библиотеки или собственные контейнеры для работы с алгоритмами библиотеки, никак не затрагивая (или даже не читая) исходный текст библиотеки.
3.2. Взаимозаменяемость компонентов
Каким же образом достигнута эта открытость и ортогональность компонентов STL? Оказывается, решение давно известно во многих промышленных отраслях: взаимозаменяемость компонентов, достигаемая путем максимально возможного упрощения и унификации интерфейсов.
Мы все знакомы с преимуществами взаимозаменяемости в промышленности, и в области программного обеспечения делались такие же попытки. Начавшись с первых набросков STL, подход, нацеленный на достижение максимальной взаимозаменяемости программных компонентов, достиг таких высот, как ни в одной другой библиотеке.
Мы уже знакомы с некоторыми аспектами взаимозаменяемости компонентов STL в алгоритмах find и merge (в разделах 2.2.1 и 2.2.2). Эти алгоритмы работают с таким множеством контейнеров, потому что их интерфейсы спроектированы для обращения к последовательностям только очень ограниченными способами, посредством указателеобразных объектов, называющихся итераторами.
Основная цель заключается в том, чтобы сделать алгоритмы STL не зависящими от структур данных, с которыми они работают. Вместо этого алгоритмы и контейнеры STL комбинируются следующим образом.
• Для каждого контейнера мы указываем, какие категории итераторов он предоставляет.
• Для каждого алгоритма мы указываем, с какими категориями итераторов он работает.
Определение алгоритмов в терминах итераторов, а не непосредственно структур данных, делает возможной независимость алгоритмов от последних. Так алгоритмы становятся особенно "обобщенными", способными работать с большим количеством разных структур данных. Ни одна другая библиотека не способна на такое расширение, как STL.
Кроме того, наблюдается единообразное использование соглашения об указании начала и конца данных. Рассмотрим алгоритм sort, который, подобно алгоритму find, работает с данными в одной последовательности (он сохраняет результаты работы в той же последовательности). Как и find, sort получает доступ к последовательности при помощи двух итераторов, указывающих начальную и конечную точки:
long a [10000] ;
vector<int> v;
deque<double> d;
// ... Код для вставки значений в a, v и d
// Сортировка всех элементов массива а:
sort(&а[0], &а[10000]);
II Сортировка всех элементов вектора v:
sort (v.begin () , v.end());
// Сортировка всех элементов дека d:
sort (d.begin () , d.end());
// Сортировка первых 100 элементов дека d:
sort (d.beginO , d.begin() + 100);
Одним словом, алгоритмы единообразны в своем обращении к данным, а контейнеры предоставляют доступ к данным согласно требованиям алгоритмов.
Концепция итераторов более детально разъясняется в главе 4, "Итераторы".
