Стандартная библиотека шаблонов

Библиотека стандартных шаблонов (англ. Standard Template Library, STL) — набор согласованных обобщённых алгоритмов, контейнеров, средств доступа к их содержимому и различных вспомогательных функций в C++.

Библиотека стандартных шаблонов до включения в стандарт C++ была сторонней разработкой, вначале — фирмы HP, а затем — SGI. Стандарт языка не называет её «STL», так как эта библиотека стала неотъемлемой частью языка, однако многие люди до сих пор используют это название, чтобы отличать её от остальной части стандартной библиотеки (потоки ввода-вывода (iostream), подраздел Си и др.).

Проект под названием STLPort, основанный на SGI STL, осуществляет постоянное обновление STL, iostream и строковых классов. Некоторые другие проекты также занимаются разработкой частных применений стандартной библиотеки для различных конструкторских задач. Каждый производитель компиляторов C++ обязательно поставляет какую-либо реализацию этой библиотеки, так как она является очень важной частью стандарта и широко используется.

Архитектура STL была разработана Александром Степановым и Менг Ли.

Структура библиотеки править

В библиотеке выделяют пять основных компонентов:

  1. Контейнер (англ. container) — хранение набора объектов в памяти.
  2. Итератор (англ. iterator) — обеспечение средств доступа к содержимому контейнера.
  3. Алгоритм (англ. algorithm) — определение вычислительной процедуры.
  4. Адаптер (англ. adaptor) — адаптация компонентов для обеспечения различного интерфейса.
  5. Функциональный объект (англ. functor) — сокрытие функции в объекте для использования другими компонентами.

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

Контейнеры править

Контейнеры библиотеки STL можно разделить на четыре категории: последовательные, ассоциативные, контейнеры-адаптеры и псевдоконтейнеры.

КонтейнерОписание
Последовательные контейнеры
vector[1]C-подобный динамический массив произвольного доступа с автоматическим изменением размера при добавлении/удалении элемента. Доступ по индексу за . Добавление-удаление элемента в конец vector занимает амортизированное время, та же операция в начале или середине vector — . Стандартная быстрая сортировка за . Поиск элемента перебором занимает . Существует специализация шаблона vector для типа bool, которая требует меньше памяти за счёт хранения элементов в виде битов, однако она не поддерживает всех возможностей работы с итераторами.
list[2]Двусвязный список, элементы которого хранятся в произвольных кусках памяти, в отличие от контейнера vector, где элементы хранятся в непрерывной области памяти. Поиск перебором медленнее, чем у вектора из-за большего времени доступа к элементу. Доступ по индексу за . В любом месте контейнера вставка и удаление производятся очень быстро — за .
deque[3]Двухсторонняя очередь. Контейнер похож на vector, но с возможностью быстрой вставки и удаления элементов на обоих концах за . Реализован в виде двусвязанного списка линейных массивов. С другой стороны, в отличие от vector, двухсторонняя очередь не гарантирует расположение всех своих элементов в непрерывном участке памяти, что делает невозможным безопасное использование арифметики указателей[4] для доступа к элементам контейнера[5][6].
Ассоциативные контейнеры
setУпорядоченное множество уникальных элементов. При вставке/удалении элементов множества итераторы, указывающие на элементы этого множества, не становятся недействительными. Обеспечивает стандартные операции над множествами типа объединения, пересечения, вычитания. Тип элементов множества должен реализовывать оператор сравнения operator<, или требуется предоставить функцию-компаратор. Реализован на основе самобалансирующего дерева двоичного поиска.
multisetТо же, что и set, но позволяет хранить повторяющиеся элементы.
mapУпорядоченный ассоциативный массив пар элементов, состоящих из ключей и соответствующих им значений. Ключи должны быть уникальны. Порядок следования элементов определяется ключами. При этом тип ключа должен реализовывать оператор сравнения operator<, либо требуется предоставить функцию-компаратор.
multimapТо же, что и map, но позволяет хранить несколько одинаковых ключей.
Контейнеры-адаптеры
stackСтек — контейнер, в котором добавление и удаление элементов осуществляется с одного конца.
queueОчередь — контейнер, с одного конца которого можно добавлять элементы, а с другого — вынимать.
priority_queueОчередь с приоритетом, организованная так, что самый большой элемент всегда стоит на первом месте.
Псевдоконтейнеры
bitsetСлужит для хранения битовых масок. Похож на vector<bool> фиксированного размера. Размер фиксируется тогда, когда объявляется объект bitset. Итераторов в bitset нет. Оптимизирован по размеру памяти.
basic_stringКонтейнер, предназначенный для хранения и обработки строк. Хранит в памяти элементы подряд единым блоком, что позволяет организовать быстрый доступ ко всей последовательности. Элементы должны быть POD'ами. Определена конкатенация с помощью +.
valarrayШаблон служит для хранения числовых массивов и оптимизирован для достижения повышенной вычислительной производительности. В некоторой степени похож на vector, но в нём отсутствует большинство стандартных для контейнеров операций. Определены операции над двумя valarray и над valarray и скаляром (поэлементные). Эти операции возможно эффективно реализовать как на векторных процессорах, так и на скалярных процессорах с блоками SIMD.

В контейнерах для хранения элементов используется семантика передачи объектов по значению. Другими словами, при добавлении контейнер получает копию элемента. Если создание копии нежелательно, то используют контейнер указателей на элементы. Присвоение элементов реализуется с помощью оператора присваивания, а их уничтожение происходит с использованием деструктора.В таблице приведены основные требования к элементам в контейнерах:

МетодОписаниеПримечание
Конструктор копииСоздаёт новый элемент, идентичный старомуИспользуется при каждой вставке элемента в контейнер
Оператор присваиванияЗаменяет содержимое элемента копией исходного элементаИспользуется при каждой модификации элемента
ДеструкторРазрушает элементИспользуется при каждом удалении элемента
Конструктор по умолчаниюСоздаёт элемент без аргументовПрименяется только для определённых операций
operator==Сравнивает два элементаИспользуется при выполнении operator== для двух контейнеров
operator<Определяет, меньше ли один элемент другогоИспользуется при выполнении operator< для двух контейнеров

Все «полноценные» стандартные контейнеры удовлетворяют определённому набору требований (или соглашений). В приведённой ниже таблице полагается, что С — класс контейнера, содержащий объекты типа Т.

ВыражениеВозвращаемый типСложностьПримечание
C::value_typeTВремя компиляции
C::referenceTВремя компиляции
C::const_referenceВремя компиляции
C::pointerТип указателя, указывающего на C::referenceВремя компиляцииУказатель на Т
C::iteratorТип итератора, указывающего на C::referenceВремя компиляцииИтератор любого типа, кроме итератора вывода
C::const_iteratorТип итератора, указывающего на C::const_referenceВремя компиляцииИтератор любого типа, кроме итератора вывода
C::size_typeБеззнаковый целочисленный типВремя компиляции
C obj;ПостояннаяПосле: obj.size() == 0
C obj1; obj1 = obj2;ЛинейнаяПосле: obj1 == obj2
C obj; (&obj)->~C();Результат не используетсяЛинейнаяПосле: obj.size() == 0.
obj.begin()Постоянная
obj.end()Постоянная
obj1 == obj2Обратимый в boolЛинейная
obj1 != obj2Обратимый в boolЛинейная
obj.size()size_typeЗависит от типаНе рекомендуется применять для проверки, пуст ли контейнер
obj.empty()Обратимый в boolПостоянная
obj1 < obj2Обратимый в boolЛинейная
obj1 > obj2Обратимый в boolЛинейная
obj1 <= obj2Обратимый в boolЛинейная
obj1 >= obj2Обратимый в boolЛинейная
obj.swap(obj2)voidПостоянная

Итераторы править

В библиотеке STL для доступа к элементам в качестве посредника используется обобщённая абстракция, именуемая итератором. Каждый контейнер поддерживает «свой» вид итератора, который представляет собой «модернизированный» интеллектуальный указатель[7], «знающий», как получить доступ к элементам конкретного контейнера. Стандарт C++ определяет пять категорий итераторов, описанных в следующей таблице:

КатегорияПоддерживаемые операцииПримечание
Входныеoperator++, operator*, operator->, конструктор копии, operator=, operator==, operator!=Обеспечивают доступ для чтения в одном направлении. Позволяют выполнить присваивание или копирование с помощью оператора присваивания и конструктора копии.
Выходныеoperator++, operator*, конструктор копииОбеспечивают доступ для записи в одном направлении. Их нельзя сравнивать на равенство.
Однонаправленныеoperator++, operator*, operator->, конструктор копии, конструктор по умолчанию, operator=, operator==, operator!=Обеспечивают доступ для чтения и записи в одном направлении. Позволяют выполнить присваивание или копирование с помощью оператора присваивания и конструктора копии. Их можно сравнивать на равенство.
Двунаправленныеoperator++, operator--, operator*, operator->, конструктор копии, конструктор по умолчанию, operator=, operator==, operator!=Поддерживают все функции, описанные для однонаправленных итераторов (см. выше). Кроме того, они позволяют переходить к предыдущему элементу.
Произвольного доступаoperator++, operator--, operator*, operator->, конструктор копии, конструктор по умолчанию, operator=, operator==, operator!=, operator+, operator-, operator+=, operator-=, operator<, operator>, operator<=, operator>=, operator[]Эквивалентны обычным указателям: поддерживают арифметику указателей, синтаксис индексации массивов и все формы сравнения.

См. также править

Примечания править

  1. std::vector. Дата обращения: 14 февраля 2016. Архивировано 27 ноября 2015 года.
  2. std: list
  3. std::deque. Дата обращения: 14 февраля 2016. Архивировано 5 февраля 2016 года.
  4. Синтаксис указателей в C++. Дата обращения: 14 февраля 2016. Архивировано 11 марта 2016 года.
  5. Iterator library. Дата обращения: 14 февраля 2016. Архивировано из оригинала 5 февраля 2016 года.
  6. C++ concepts: Iterator. Дата обращения: 14 февраля 2016. Архивировано 19 февраля 2016 года.
  7. Types of iterator : Output vs. Input vs. Forward vs. Random Access Iterator. Дата обращения: 14 февраля 2016. Архивировано 23 февраля 2016 года.

Литература править

  • Скотт Мейерс. Эффективное использование STL = Effective STL. — Питер, 2002. — С. 224. — (Библиотека программиста). — ISBN 5-94723-382-7.
  • Дэвид Р. Мюссер, Жилмер Дж. Дердж, Атул Сейни. C++ и STL: справочное руководство = STL Tutorial and Reference Guide: C++ Programming with the Standard Template. — 2-е издание. — М.: «Вильямс», 2010. — С. 432. — (серия C++ in Depth). — ISBN 5-89818-027-3.
  • Леен Аммерааль. STL для программистов на C++ = STL for C++ programmers. — ДМК Пресс, 1999. — С. 240. — ISBN 5-256-00704-1.

Ссылки править