9.2. Обзор библиотечных контейнеров
Возможные операции с контейнерами составляют своего рода иерархию.
• Некоторые функциональные возможности (табл. 9.2) поддерживаются контейнерами всех типов.
• Другие операции являются специфическими только для последовательных (табл. 9.3), ассоциативных (табл. 11.7) или неупорядоченных (табл. 11.8) контейнеров.
• Остальные являются общими лишь для небольшого подмножества контейнеров.
Таблица 9.2. Средства контейнеров
Псевдонимы типов iterator Тип итератора для контейнера данного типа const_iterator Тип итератора, позволяющий читать, но не изменять значение элемента size_type Целочисленный беззнаковый тип, размер которого достаточно велик, чтобы содержать значение размера наибольшего возможного контейнера данного типа difference_type Целочисленный знаковый тип, размер которого достаточно велик, чтобы содержать значение разницы между двумя итераторами value_type Тип элемента reference Тип l-значения элемента; то же, что и value_type& const_reference Тип константного l-значения элемента; аналог const value_type& Конструкторы С с; Стандартный конструктор, создающий пустой контейнер С c1(c2); Создает контейнер c1 как копию контейнера c2 С c(b, е); Копирует элементы из диапазона, обозначенного итераторами b и е (недопустимо для массива) C c{а, b, c...}; Списочная инициализация контейнера с Присвоение и замена c1 = c2 Заменяет элементы контейнера c1 элементами контейнера c2 c1 = {a, b, c...} Заменяет элементы контейнера c1 элементами списка (недопустимо для массива) a.swap(b) Меняет местами элементы контейнеров а и b swap(а, b) Эквивалент a.swap(b) Размер c.size() Возвращает количество элементов контейнера c (недопустимо для контейнера forward_list) c.max_size() Возвращает максимально возможное количество элементов контейнера с c.empty() Возвращает логическое значение false, если контейнер c пуст. В противном случае возвращает значение true Добавление/удаление элементов (недопустимо для массива) Примечание: интерфейс этих функций зависит от типа контейнера c.insert(args) Копирует элемент(ы), указанный параметром args, в контейнер c c.emplace(inits) Использует параметр inits для создания элемента в контейнере с c.erase(args) Удаляет элемент(ы), указанный параметром args, из контейнера c c.clear() Удаляет все элементы из контейнера c; возвращает значение void Операторы равенства и отношения ==, != Равенство допустимо для контейнеров всех типов <, <=, >, >= Операторы отношения (недопустимы для неупорядоченных ассоциативных контейнеров) Получения итераторов c.begin(), c.end() Возвращают итератор на первый и следующий после последнего элемент в контейнере с c.cbegin(), c.cend() Возвращают const_iterator Дополнительные члены реверсивных контейнеров (недопустимы для forward_list) reverse_iterator Итератор, обеспечивающий доступ к элементам в обратном порядке const_reverse_iterator Реверсивный итератор, не позволяющий запись в элементы с.rbegin(), c.rend() Возвращает итератор на последний и следующий после первого элементы контейнера c c.crbegin(), c.crend() Возвращают итератор const_reverse_iteratorВ этом разделе рассматриваются аспекты, являющиеся общими для всех контейнеров. Остальная часть этой главы посвящена исключительно последовательным контейнерам; операции, специфические для ассоциативных контейнеров, рассматриваются в главе 11.
Обычно каждый контейнер определяется в файле заголовка, название которого совпадает с именем типа. Таким образом, тип deque определен в заголовке deque, тип list — в заголовке list и т.д. Контейнеры — это шаблоны классов (см. раздел 3.3). Подобно векторам, при создании контейнера специфического типа необходимо предоставить дополнительную информацию. Для большинства контейнеров, но не всех, предоставляемой информацией является тип элемента:
list<Sales_data> // список, содержащий объекты класса Sales_data
deque<double> // двухсторонняя очередь переменных типа double
Ограничения на типы, которые может содержать контейнер
Типом элемента последовательного контейнера может быть практически любой тип. В частности, типом элемента контейнера может быть другой контейнер. Такие контейнеры определяют точно так же, как любые другие: в угловых скобках указывается тип элемента (которым в данном случае является другой контейнер):
vector<vector<string>> lines; // вектор векторов
где lines — это вектор, элементами которого являются векторы строк.
Устаревшие компиляторы могут потребовать пробела между угловыми скобками, например vector<vector<string> >.
Несмотря на то что в контейнере можно хранить практически любой тип, некоторые операции налагают на тип элемента собственные требования. Можно определить контейнер для типа, который не поддерживает определенное операцией требование, но использовать операцию можно, только если тип элемента отвечает требованиям этой операции.
В качестве примера рассмотрим конструктор последовательного контейнера, получающий аргумент размера (см. раздел 3.3.1) и использующий стандартный конструктор типа элемента. У некоторых классов нет стандартного конструктора. Вполне можно определить контейнер, содержащий объекты такого типа, но создать такой контейнер, используя только количество элементов, нельзя:
// тип noDefault не имеет стандартного конструктора
vector<noDefault> v1(10, init); // ok: предоставлен инициализатор
// элемента
vector<noDefault> v2(10); // ошибка: необходимо предоставить
// инициализатор элемента
Поскольку рассматриваются контейнерные операции, следует заметить, что тип элемента накладывает дополнительные ограничения, если таковые вообще имеются, на каждую операцию с контейнером.
Упражнения раздела 9.2
Упражнение 9.2. Определите список (list), элементами которого будут двухсторонние очереди целых чисел.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОК