
- •4.6. Иерархия итераторов stl: эффективная комбинация алгоритмов и контейнеров
- •4.7. Итераторы вставки
- •4.8. Еще раз о входе и выходе: потоковые итераторы
- •4.9. Спецификация категорий итераторов, требуемых алгоритмами stl
- •4.10. Разработка обобщенных алгоритмов
- •4.11. Почему некоторые алгоритмы требуют более мощные итераторы
- •4.12. Выбор правильного алгоритма
- •4.13. Константные и изменяемые итераторы
- •4.14. Категории итераторов, предоставляемые контейнерами stl
4.6. Иерархия итераторов stl: эффективная комбинация алгоритмов и контейнеров
Ключом к пониманию итераторов и их роли в STL является понимание того, почему следует разбивать итераторы на категории входных/выходных, одно- и двунаправленных, а также произвольного доступа. Эта классификация образует иерархию итераторов, т.е.:
• однонаправленные итераторы одновременно являются входными и выходными итераторами;
• двунаправленные итераторы одновременно являются однонаправленными
итераторами, а следовательно, входными и выходными итераторами;
• итераторы с произвольным доступом являются двунаправленными итераторами, а следовательно, и однонаправленными итераторами, и входными и выходными итераторами.
Эта иерархия приводит к следующему:
• алгоритмы, требующие для работы входные или выходные итераторы, могут также работать с однонаправленными итераторами, двунаправленными итераторами и итераторами с произвольным доступом;
• алгоритмы, требующие для работы однонаправленные итераторы, могут также работать с двунаправленными итераторами и итераторами с произвольным доступом;
• алгоритмы, требующие для работы двунаправленные итераторы, могут также работать с итераторами с произвольным доступом.
Таким образом, категории итераторов используются в спецификациях контейнеров и алгоритмов следующим образом:
• описание классов контейнеров включает категорию предоставляемых ими итераторов;
• описание обобщенных алгоритмов включает категории итераторов, с которыми они работают.
Вот несколько примеров.
• list предоставляет двунаправленные итераторы, а алгоритм find требует входные итераторы; следовательно, find можно использовать с list.
• list предоставляет двунаправленные итераторы, а алгоритм sort требует итераторы с произвольным доступом. Поскольку двунаправленные итераторы в общем случае не обладают свойствами итераторов с произвольным доступом, алгоритм sort не может использоваться с контейнерами list. Код наподобие
list<int> list1;
// ... Код для вставки значений в list1
sort(list1.begin(), list1.end());
компилироваться не будет.
• deque предоставляет итераторы с произвольным доступом, которые требует алгоритм sort. Это означает, что sort будет работать с deque; более того, эта комбинация будет работать эффективно.
• Итераторы set двунаправленные, а алгоритм merge требует входные итераторы или более высокие. Поскольку двунаправленные итераторы в иерархии находятся выше входных, понятно, что алгоритм merge может быть применен к контейнерам set. Такая комбинация допустима и эффективна.
Иерархия итераторов подчеркивает фундаментальную идею в основе дизайна STL: интерфейсы контейнеров и алгоритмов STL спроектированы так, чтобы поддерживать эффективные комбинации и препятствовать неэффективным. Поддержка означает, что эффективные комбинации компилируются без ошибок. Хотя компилируются и некоторые неэффективные комбинации, в большинстве случаев они приводят к ошибкам компиляции и требуют больших усилий, поскольку программист вынужден писать дополнительный код для компенсации отсутствующих операторов.
Категории итераторов и вопросы эффективности рассматриваются дальше, в разделе 4.11.