Стандартная библиотека шаблонов - Standard Template Library

В Стандартная библиотека шаблонов (STL) это библиотека программного обеспечения для C ++ язык программирования, повлиявший на многие части Стандартная библиотека C ++. Он предоставляет четыре компонента, которые называются алгоритмы, контейнеры, функции, и итераторы.[1]

STL предоставляет набор общих классы для C ++, например контейнеры и ассоциативные массивы, который можно использовать с любым встроенным типом и с любым определяемым пользователем типом, который поддерживает некоторые элементарные операции (например, копирование и присваивание). Алгоритмы STL не зависят от контейнеров, что значительно снижает сложность библиотеки.

STL достигает своих результатов за счет использования шаблоны. Такой подход обеспечивает полиморфизм времени компиляции это часто более эффективно, чем традиционные полиморфизм времени выполнения. Современный C ++ компиляторы настроены так, чтобы минимизировать штрафы за абстракцию, возникающие из-за интенсивного использования STL.

STL была создана как первая библиотека общих алгоритмов и структур данных для C ++ с четырьмя идеями: общее программирование, абстрактность без потери эффективности Вычислительная модель фон Неймана,[2] и семантика значений.

История

В ноябре 1993 г. Александр Степанов представил библиотеку на основе универсального программирования Комитет ANSI / ISO для стандартизации C ++. Ответ комитета был в целом положительным и привел к запросу от Эндрю Кениг для официального предложения к встрече в марте 1994 года. У комитета было несколько запросов об изменениях и расширениях, и члены комитета встретились со Степановым и Мэн Ли чтобы помочь проработать детали. Требования к наиболее значительному расширению (ассоциативные контейнеры ) необходимо было продемонстрировать свою последовательность, полностью выполнив их, - задача, которую Степанов поручил Дэвид Массер. Предложение было окончательно одобрено на заседании комитета ANSI / ISO в июле 1994 года. Впоследствии документ Степанова и Ли 17 был включен в черновой вариант стандарта ANSI / ISO C ++ (1, части пунктов с 17 по 27).

Перспективы скорейшего повсеместного распространения STL были значительно улучшены с решением Hewlett-Packard сделать его реализацию свободно доступной на Интернет в августе 1994 года. Эта реализация, разработанная Степановым, Ли и Массером в процессе стандартизации, стала основой многих реализаций, предлагаемых сегодня поставщиками компиляторов и библиотек.

Сочинение

Контейнеры

STL содержит последовательность контейнеры и ассоциативные контейнеры. Контейнеры - это объекты, в которых хранятся данные. Стандарт контейнеры последовательности включают вектор, дек, и список. Стандарт ассоциативные контейнеры находятся набор, мультимножество, карта, Multimap, hash_set, hash_map, hash_multiset и hash_multimap. Это также адаптеры для контейнеров очередь, priority_queue, и стек, которые представляют собой контейнеры с определенным интерфейсом, использующие другие контейнеры в качестве реализации.

КонтейнерОписание
Простые контейнеры
параКонтейнер пар - это простой ассоциативный контейнер, состоящий из 2-кортеж элементов данных или объектов, называемых «первым» и «вторым», в этом фиксированном порядке. «Пара» STL может быть назначена, скопирована и сравнена. Массив объектов, размещенных на карте или hash_map (описанном ниже), по умолчанию имеет тип «пара», где все «первые» элементы действуют как уникальные ключи, каждый из которых связан со своими «вторыми» объектами значений.
Последовательности (массивы /связанные списки ): заказанные коллекции
вектора динамический массив, любить C массив (т.е. способный произвольный доступ ) с возможностью автоматического изменения размера при вставке или стирании объекта. Вставка элемента в конец вектора требует амортизированное постоянное время. Удаление последнего элемента занимает только постоянное время, потому что изменение размера не происходит. Вставка и стирание в начале или в середине линейны во времени.

Специализация для шрифта bool существует, который оптимизирует пространство за счет хранения bool значения как биты.

списока двусвязный список; элементы не хранятся в непрерывной памяти. Противоположное представление от вектора. Медленный поиск и доступ (линейное время), но как только позиция была найдена, быстрая вставка и удаление (постоянное время).
Slist
а односвязный список; элементы не хранятся в непрерывной памяти. Противоположное представление от вектора. Медленный поиск и доступ (линейное время), но как только позиция была найдена, быстрая вставка и удаление (постоянное время). Он имеет немного более эффективную вставку и удаление и использует меньше памяти, чем двусвязный список, но его можно повторять только вперед. Он реализован в стандартной библиотеке C ++ как forward_list.
дек (двусторонний очередь )вектор со вставкой / стиранием в начале или в конце амортизированное постоянное время, однако отсутствуют некоторые гарантии действительности итератора после изменения двухсторонней очереди.
Адаптеры для контейнеров
очередьОбеспечивает ФИФО очередь интерфейс с точки зрения От себя/поп/фронт/назад операции.

Любая последовательность поддерживающих операций фронт(), назад(), отталкивать(), и pop_front() может использоваться для создания очереди (например, список и дек).

приоритетная очередьОбеспечивает приоритетная очередь интерфейс с точки зрения От себя/поп/верх операций (вверху находится элемент с наивысшим приоритетом).

Любые произвольный доступ последовательность поддерживающих операций фронт(), отталкивать(), и pop_back() может использоваться для создания экземпляра priority_queue (например, вектор и дек). Реализуется с помощью куча.

Элементы должны дополнительно поддерживать сравнение (чтобы определить, какой элемент имеет более высокий приоритет и должен быть отображен первым).

стекОбеспечивает LIFO стек интерфейс с точки зрения От себя/поп/верх операции (последний вставленный элемент находится сверху).

Любая последовательность поддерживающих операций назад(), отталкивать(), и pop_back() может использоваться для создания экземпляра стека (например, вектор, список, и дек).

Ассоциативные контейнеры: неупорядоченные коллекции
наборматематический набор; вставка / стирание элементов в наборе не делает недействительными итераторы, указывающие на набор. Обеспечивает набор операций союз, пересечение, разница, симметричная разница и тест на включение. Тип данных должен реализовывать оператор сравнения < или должна быть указана пользовательская функция компаратора; такой оператор сравнения или функция компаратора должны гарантировать строгий слабый порядок, иначе поведение не определено. Обычно реализуется с использованием самобалансирующееся двоичное дерево поиска.
мультимножеството же, что и набор, но допускает дублирование элементов (математический мультимножество ).
картаан ассоциативный массив; позволяет отображать один элемент данных (ключ) в другой (значение). Тип ключа должен реализовывать оператор сравнения < или должна быть указана пользовательская функция компаратора; такой оператор сравнения или функция компаратора должны гарантировать строгий слабый порядок, иначе поведение не определено. Обычно реализуется с использованием самобалансирующегося двоичного дерева поиска.
MultimapТо же, что и карта, но допускает дублирование ключей.
hash_set
hash_multiset
hash_map
hash_multimap
аналогичен набору, мультимножеству, карте или мульти-карте, соответственно, но реализован с использованием хеш-таблица; ключи не заказываются, а хеш-функция должен существовать для типа ключа. Эти типы были исключены из стандарта C ++; аналогичные контейнеры были стандартизированы в C ++ 11, но с разными именами (unordered_set и unordered_map).
Другие типы контейнеров
битсетхранит серию битов, аналогичную вектору bool фиксированного размера. Реализует побитовые операции и не имеет итераторов. Не последовательность. Предоставляет произвольный доступ.
ValarrayДругой тип данных массива, предназначенный для числового использования (особенно для представления векторов и матрицы ); стандарт C ++ допускает определенные оптимизации для этой намеченной цели. По словам Йосуттиса, Valarray был плохо спроектирован людьми, «которые покинули комитет [стандарт C ++] задолго до того, как стандарт был закончен», и шаблон выражения библиотеки должны быть предпочтительнее.[3] Предлагаемая переписать Valarray часть стандарта в этом ключе была отклонена, вместо этого ставшая разрешением на его реализацию с использованием шаблона выражения.[4]

Итераторы

STL реализует пять различных типов итераторы. Эти итераторы ввода (который можно использовать только для чтения последовательности значений), итераторы вывода (который можно использовать только для записи последовательности значений), прямые итераторы (которые можно читать, писать и двигаться вперед), двунаправленные итераторы (которые похожи на итераторы вперед, но могут также двигаться назад) и итератор произвольного доступаs (который может свободно перемещаться на любое количество шагов за одну операцию).

Фундаментальная концепция STL - это ассортимент который представляет собой пару итераторов, которые обозначают начало и конец вычисления, и большинство алгоритмических шаблонов библиотеки, которые работают со структурами данных, имеют интерфейсы, которые используют диапазоны.[5]

Возможно, чтобы двунаправленные итераторы действовали как итераторы с произвольным доступом, поэтому можно было бы продвинуться на десять шагов, просто продвигаясь вперед на шаг за раз в общей сложности десять раз. Однако наличие отдельных итераторов произвольного доступа дает преимущества в эффективности. Например, вектор будет иметь итератор с произвольным доступом, а список - только двунаправленный итератор.

Итераторы - это основная функция, обеспечивающая универсальность STL. Например, алгоритм реверсирования последовательности может быть реализован с использованием двунаправленных итераторов, а затем такая же реализация может использоваться для списков, векторов и дек. Создано пользователем контейнеры нужно только предоставить итератор, который реализует один из пяти стандартных интерфейсов итератора, и все алгоритмы, представленные в STL, могут использоваться в контейнере.

За эту универсальность иногда приходится расплачиваться. Например, поиск по ассоциативный контейнер такие как карта или набор, могут быть намного медленнее при использовании итераторов, чем при вызове функций-членов, предлагаемых самим контейнером. Это связано с тем, что методы ассоциативного контейнера могут использовать информацию о внутренней структуре, которая непрозрачна для алгоритмов, использующих итераторы.

Алгоритмы

В STL предусмотрено большое количество алгоритмов для выполнения таких действий, как поиск и сортировка, каждый из которых реализован так, чтобы требовать определенного уровня итератора (и, следовательно, будет работать с любым контейнером, который предоставляет интерфейс с помощью итераторов). Поисковые алгоритмы вроде binary_search и нижняя граница использовать бинарный поиск и подобные алгоритмы сортировки требуют, чтобы тип данных реализовывал оператор сравнения < или должна быть указана пользовательская функция компаратора; такой оператор сравнения или функция компаратора должны гарантировать строгий слабый порядок. Помимо этого, предусмотрены алгоритмы для создания кучи из диапазона элементов, генерации лексикографически упорядоченных перестановок диапазона элементов, объединения отсортированных диапазонов и выполнения союз, пересечение, разница отсортированных диапазонов.

Функции

STL включает классы, которые перегрузка оператор вызова функции (оператор()). Экземпляры таких классов называются функторами или функциональные объекты. Функторы позволяют параметризовать поведение связанной функции (например, через аргументы, передаваемые в конструктор ) и может использоваться для сохранения связанной информации о состоянии каждого функтора вместе с функцией. Поскольку как функторы, так и указатели функций могут быть вызваны с использованием синтаксиса вызова функции, они взаимозаменяемы в качестве аргументов шаблонов, когда соответствующий параметр появляется только в контекстах вызова функций.

Особенно распространенным типом функторов является предикат. Например, такие алгоритмы, как find_if взять унарный предикат, который работает с элементами последовательности. Алгоритмы вроде sort, partial_sort, nth_element и all sorted контейнеры использовать двоичный предикат, который должен предоставлять строгий слабый порядок, то есть он должен вести себя как членство тест на переходный, нерефлексивный и асимметричный бинарное отношение. Если ничего не указано, эти алгоритмы и контейнеры используют Меньше по умолчанию, который, в свою очередь, вызывает оператор «меньше» <.

Критика

Качество реализации компиляторов C ++

Качество реализации (QoI) компилятора C ++ имеет большое влияние на удобство использования STL (и шаблонного кода в целом):

  • Сообщения об ошибках с использованием шаблонов, как правило, очень длинные и их трудно расшифровать. Эта проблема считалась настолько серьезной, что был написан ряд инструментов, упрощающих и Prettyprint Сообщения об ошибках, связанные с STL, чтобы сделать их более понятными.
  • Неосторожное использование шаблонов может привести к раздувание кода.[6] Этому противодействуют специальные методы в реализациях STL (например, внутреннее использование контейнеров void * и другие методы «шаблона диеты») и улучшение методов оптимизации компиляторов. Однако этот симптом похож на наивное ручное копирование набора функций для работы с другим типом, поскольку и того и другого можно избежать осторожно и с хорошей техникой.
  • Создание экземпляра шаблона может увеличить время компиляции и использование памяти в обмен на сокращение времени принятия решений (например, с помощью виртуальных функций). Пока технология компилятора не улучшится в достаточной степени, эту проблему можно лишь частично устранить путем тщательного кодирования, избегания определенных идиом и просто отказа от использования шаблонов там, где они не подходят или где производительность во время компиляции является приоритетной.

Другие вопросы

  • Инициализация STL контейнеры с константами в исходном коде не так просто, как структуры данных, унаследованные от C (адресованные в C ++ 11 с участием списки инициализаторов ).
  • Контейнеры STL не предназначены для использования в качестве базовых классов (их деструкторы намеренно не являются виртуальными); извлечение из контейнера - распространенная ошибка.[7][8]
  • В концепция Итераторов, реализованных в STL, может быть трудно понять сначала: например, если значение, на которое указывает итератор, удаляется, сам итератор становится недействительным. Это частый источник ошибок. Большинство реализаций STL предоставляют более медленный режим отладки, но при его использовании могут обнаруживать такие ошибки. Аналогичная проблема существует и на других языках, например Ява. Диапазоны были предложены как более безопасная и гибкая альтернатива итераторам.[9]
  • Некоторые шаблоны итераций не отображаются на модель итератора STL.[нужна цитата ] Например, API перечисления обратных вызовов невозможно адаптировать к модели STL без использования сопрограммы,[10] которые зависят от платформы или недоступны и будут выходить за рамки стандарта C ++ до C ++ 20.
  • Соответствие компилятора не гарантирует, что Распределитель объекты, используемые для управления памятью для контейнеры, будет работать с поведением, зависящим от состояния. Например, переносимая библиотека не может определить тип распределителя, который будет извлекать память из разных пулов, используя разные объекты распределителя этого типа. (Мейерс, стр. 50) (рассмотрено в C ++ 11 ).
  • Набор алгоритмов не полный: например, copy_if алгоритм был опущен,[11] хотя он был добавлен в C ++ 11.[12]

Реализации

Смотрите также

Заметки

  1. ^ Хольцнер, Стивен (2001). C ++: Черная книга. Скоттсдейл, Аризона: Coriolis Group. п. 648. ISBN  1-57610-777-9. STL состоит из контейнеры, итераторы, функциональные объекты, и алгоритмы
  2. ^ Мюссер, Дэвид (2001). Учебное и справочное руководство по STL: программирование на C ++ с использованием стандартной библиотеки шаблонов. Эддисон Уэсли. ISBN  0-201-37923-6.
  3. ^ Йосуттис, Николай М. (1999). Стандартная библиотека C ++: Учебное пособие и справочник. Эддисон-Уэсли Профессионал. п.547.
  4. ^ Вандевурде, Дэвид; Йосуттис, Николай М. (2002). Шаблоны C ++: полное руководство. Эддисон Уэсли. ISBN  0-201-73484-2.
  5. ^ Степанов, Александр; Ли, Мэн (31 октября 1995 г.). «Стандартная библиотека шаблонов» (PDF). Получено 16 декабря 2018. Большинство алгоритмических шаблонов библиотеки, которые работают со структурами данных, имеют интерфейсы, которые используют диапазоны. Диапазон - это пара итераторов, обозначающих начало и конец вычисления. [...] в общем случае диапазон [i, j) относится к элементам в структуре данных, начиная с элемента, на который указывает i, и до, но не включая элемент, на который указывает j. Диапазон [i, j) действителен тогда и только тогда, когда j достижим из i.
  6. ^ Адриан Стоун. «Сведение к минимуму раздувания кода: чрезмерная специализация шаблона».
  7. ^ Мейерс, Скотт (2005). Эффективное третье издание C ++ - 55 конкретных способов улучшить ваши проекты. Эддисон Уэсли. ISBN  0-321-33487-6.
  8. ^ Саттер, Херб; Александреску, Андрей (2004). Стандарты программирования C ++: 101 правила, рекомендации и передовые методы. Эддисон-Уэсли. ISBN  0-321-11358-6.
  9. ^ Андрей Александреску (6 мая 2009 г.). «Итераторы должны уйти» (PDF). BoostCon 2009. Получено 19 марта 2011.
  10. ^ Мэтью Уилсон (Февраль 2004 г.). «API-интерфейсы обратного вызова и концепция итератора ввода». Журнал доктора Добба.
  11. ^ Бьярне Страуструп (2000). Язык программирования C ++ (3-е изд.). Эддисон-Уэсли. ISBN  0-201-70073-5.:стр.530
  12. ^ Больше алгоритмов STL (версия 2)
  13. ^ Стандартная библиотека Apache C ++. Stdcxx.apache.org. Проверено 29 июля 2013.

использованная литература

внешние ссылки