Выбрать главу
Контейнерные классы

Как упоминалось выше, контейнеры представляют собой объекты STL, которые предназначены для хранения данных. Контейнеры, определяемые в STL, представлены в табл. 21.1. В ней также указаны заголовки, которые необходимо включать в программу при использовании каждого контейнера. Но несмотря на то, что класс string также является контейнером, позволяющим хранить и обрабатывать символьные строки, он в эту таблицу не включен и рассматривается ниже в этой главе.

Поскольку имена типов в объявлениях шаблонных классов произвольны, контейнерные классы объявляют typedef-версии этих типов, что конкретизирует имена типов. Некоторые из наиболее популярных typedef-имен приведены ниже.

Поскольку в одной главе невозможно рассмотреть все контейнеры, в следующих разделах мы представим только три из них: vector, list и map. Если вы поймете, как работают эти три контейнера, у вас не будет проблем с использованием остальных.

Векторы

Векторы представляют собой динамические массивы.

Одним из контейнеров самого широкого назначения является вектор. Класс vector поддерживает динамический массив, который при необходимости может увеличивать свой размер. Как вы знаете, в C++ размер массива фиксируется во время компиляции. И хотя это самый эффективный способ реализации массивов, он в то же время является и самым ограничивающим, поскольку размер массива нельзя изменять во время выполнения программы. Эта проблема решается с помощью вектора, который по мере необходимости обеспечивает выделение дополнительного объема памяти. Несмотря на то что вектор — это динамический массив, тем не менее, для доступа к его элементам можно использовать стандартное обозначение индексации массивов.

Вот как выглядит шаблонная спецификация для класса vector:

template <class Т, class Allocator = allocator<T> > class vector

Здесь T— тип сохраняемых данных, а элемент Allocator означает распределитель памяти, который по умолчанию использует стандартный распределитель. Класс vector имеет следующие конструкторы.

explicit vector(const Allocator &a = Allocator());

explicit vector(size_type num, const T &val = T(), const Allocator &a = Allocator());

vector(const vector<T, Allocator> &ob);

template <class InIter> vector(InIter start, InIter end, const Allocator &a = Allocator());

Первая форма конструктора предназначена для создания пустого вектора. Вторая создает вектор, который содержит num элементов со значением val, причем значение val может быть установлено по умолчанию. Третья форма позволяет создать вектор, который содержит те же элементы, что и заданный вектор ob. Четвертая предназначена для создания вектора, который содержит элементы в диапазоне, заданном параметрами-итераторами start и end.

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

Несмотря на то что приведенный выше синтаксис шаблона выглядит довольно "массивно", в объявлении вектора нет ничего сложного. Рассмотрим несколько примеров.

vector<int> iv; /* Создание вектора нулевой длины для хранения int-значений. */

vector<char> cv(5); /* Создание 5-элементного вектора для хранения char-значений. */

vector<char> cv(5, 'х'); /* Инициализация 5-элементного char-вектора. */

vector<int> iv2(iv); /* Создание int-вектора на основе int-вектора iv. */

Для класса vector определены следующие операторы сравнения:

==, <, <=, !=, > и >=

Для вектора также определен оператор индексации "[]", который позволяет получить доступ к элементам вектора с помощью стандартной записи с использованием индексов. Функции-члены, определенные в классе vector, перечислены в табл. 21.2. Самыми важными из них являются size(), begin(), end(), push_back(), insert() и erase(). Очень полезна функция size(), которая возвращает текущий размер вектора, поскольку она позволяет определить размер вектора во время выполнения программы. Помните, что векторы при необходимости увеличивают свой размер, поэтому нужно иметь возможность определять его величину во время работы программы, а не только во время компиляции.