Чтобы справиться с этим затруднением, функция vector::operator[] возвращает объект, который имитируетссылку на отдельный бит — так называемый промежуточный объект. Для использования STL не обязательно понимать, как работают промежуточные объекты, но вообще это весьма полезная идиома C++. Дополнительная информация о промежуточных объектах приведена в совете 30 «More Effective C++», а также в разделе «Паттерн Proxy» книги «Приемы объектно-ориентированного проектирования» [6]. На простейшем уровне vector выглядит примерно так:

template

vector {

public:

 class reference {…};// Класс, генерирующий промежуточные

                     // объекты для ссылок на отдельные биты

 reference operator[](size_type n); // operator[] возвращает

 …                                  // промежуточный объект

};

Теперь понятно, почему следующий фрагмент не компилируется:

vector v;

bool *pb=&v[0]; // Ошибка! Выражение в правой части относится к типу

                // vector::reference*, а не bool*

А раз фрагмент не компилируется, vector не удовлетворяет требованиям к контейнерам STL. Да, специфика vector особо оговорена в Стандарте; да, этот контейнер почтиудовлетворяет требованиям к контейнерам STL, но «почти» не считается. Чем больше вы напишете шаблонов, предназначенных для работы с STL, тем глубже вы осознаете эту истину. Уверяю вас, наступит день, когда написанный вами шаблон будет работать лишь в том случае, если получение адреса элемента контейнера дает указатель на тип элемента; и когда этот день придет, вы наглядно ощутите разницу между контейнером и почтиконтейнером.

Спрашивается, почему же vector присутствует в Стандарте, если это не контейнер? Отчасти это связано с одним благородным, но неудачным экспериментом, но позвольте мне ненадолго отложить эту тему и заняться более насущным вопросом. Итак, от vector следует держаться подальше, потому что это не контейнер — но что же делать, когда вам действительно понадобитсявектор логических величин?

В стандартную библиотеку входят два альтернативных решения, которые подходят практически для любых ситуаций. Первое решение — deque. Контейнер deque обладает практически всеми возможностями vector (за исключением разве что reserve и capacity), но при этом deque является полноценным контейнером STL, содержащим настоящие значения bool. Конечно, внутренняя память deque не образует непрерывный блок, поэтому данные deque не удастся передать функции C, получающей массив bool (см. совет 16), но это не удалось бы сделать и с vector из-за отсутствия переносимого способа получения данных vector. (Прием, продемонстрированный для vector в совете 16, не компилируется для vector, поскольку он зависит от возможности получения на тип элемента, хранящегося в векторе, — как упоминалось выше, vector не содержит bool.)

Второй альтернативой для vector является bitset. Вообще говоря, bitset не является стандартным контейнером STL, но входит в стандартную библиотеку C++. В отличие от контейнеров STL, размер bitset (количество элементов) фиксируется на стадии компиляции, поэтому операции вставки-удаления элементов не поддерживаются. Более того, поскольку bitset не является контейнером STL, в нем отсутствует поддержка итераторов. Тем не менее bitset, как и vector, использует компактное представление каждого элемента одним битом, поддерживает функцию flip контейнера vector и ряд других специальных функций, имеющих смысл в контексте битовых множеств. Если вы переживете без итераторов и динамического изменения размеров, вероятно, bitset хорошо подойдет для ваших целей.

А теперь вернемся к благородному, но неудачному эксперименту, из-за которого появился «псевдоконтейнер» vector. Я уже упоминал о том, что промежуточные объекты часто используются при программировании на C++. Члены Комитета по стандартизации C++ знали об этом, поэтому они решили создать vector как наглядный пример контейнера, доступ к элементам которого производится через промежуточные объекты. Предполагалось, что при наличии такого примера в Стандарте у программистов появится готовый образец для построения собственных аналогов.

Перейти на страницу:

Похожие книги