Контейнеры STL. Класс vector<bool>

   
На этом шаге мы рассмотрим особенности представления и использования класса vector<bool>.

   
Для векторов, содержащих элементы логического типа, в стандартной библиотеке C++ определена специализированная
разновидность класса vector. Это было сделано для того, чтобы оптимизированная версия занимала меньше места, чем
стандартная реализация vector для типа bool. В стандартной реализации для каждого элемента резервируется
минимум 1 байт. Во внутреннем представлении специализированной реализации vector<bool> каждый элемент обычно
представляется одним битом, поэтому она занимает в восемь раз меньше памяти. Впрочем, оптимизация не дается даром: в C++
минимальное адресуемое значение должно иметь размер минимум 1 байт. Следовательно, специализированная версия требует
специальной обработки ссылок и итераторов.

   
В результате vector<bool> не удовлетворяет всем требованиям других векторов (в частности, значение
vector<bool>preference не является полноценным l-значением, а итератор vector<bool>::iterator
не является итератором произвольного доступа). Следовательно, код шаблона работает с векторами любого типа, за исключением bool.
Вдобавок класс vector<bool> может уступать обычным реализациям по скорости работы, потому что операции с
элементами приходится преобразовывать в операции с битами. Впрочем, внутреннее устройство vector<bool> зависит от
реализации, поэтому эффективность (как скорость работы, так и затраты памяти) может быть разной.

   
Учтите, что класс vector<bool> представляет собой нечто большее, чем специализацию класса vector<> для
bool. В него также включена поддержка специальных операций, упрощающих работу с флагами и наборами битов.

   
Размер контейнера vector<bool> изменяется динамически, поэтому его можно рассматривать как битовое поле с
динамическим размером. Иначе говоря, вы можете добавлять и удалять биты. Если вы работаете с битовым полем, имеющим
статический размер, вместо класса vector<bool> лучше использовать bitset.

   
Дополнительные операции контейнера vector<bool> перечислены в таблице 1. Операция flip(), производящая
логическую инверсию, может применяться как ко всем битам, так и к отдельному биту вектора.

Таблица 1. Специальные операции vector<bool>

Операция Описание
c.flip() Инвертирует все логические элементы
m[idx].flip() Инвертирует логический элемент с заданным индексом
m[idx] = val Присваивает значение логическому элементу с индексом idx (присваивание одного бита)
m[idxl] = m[idx2] Присваивает значение элемента с индексом idx2 элементу с индексом idxl

   
Обратите внимание на возможность вызова flip() для одного логического элемента. На первый взгляд это выглядит странно,
потому что оператор индексирования возвращает значение типа bool, а вызов flip() для этого базового типа
невозможен. В данном случае класс vector<bool> использует стандартную методику, основанную на применении так
называемых заместителей: для vector<bool> возвращаемое значение оператора индексирования (и других операторов,
возвращающих элементы) оформлено в виде вспомогательного класса. Если вы хотите, чтобы возвращаемое значение интерпретировалось
как значение типа bool, используется автоматическое преобразование типа. Для других операций определяются функции класса.
Соответствующая часть объявления vector<bool> выглядит так:

namespace std {
  class vector<bool> { public:
    // Вспомогательный тип для оператора индексирования 
    class reference {
      .   .   .   .   .
      public:
        // Автоматическое преобразование типа к bool 
        operator bool() const;

        // Присваивание
        reference& operator= (const bool);
        reference& operator= (const reference&);

        // Инверсия бита 
        void flip();
    }
    .    .    .    .
    // Операции обращения к элементам
    // - возвращается тип reference вместо bool
    reference operator[] (size_type n);
    reference at(size_type n);
    reference front();
    reference back();
    .    .    .    .
  }    
}

   
Как видно из этого фрагмента, все функции обращения к элементам возвращают тип reference. Следовательно, вы также
можете использовать следующие команды:

  c.front().flip();   // Инверсия первого логического элемента
  c.at(5) = c.back(); // Присвоить последний элемент элементу с индексом 5

   
Как обычно, вызывающая сторона должна проследить за тем, чтобы в векторе существовали первый, последний и шестой
элементы.

   
Внутренний тип reference используется только для неконстантных контейнеров типа vector<bool>.
Константные функции обращения к элементам возвращают обычные значения типа bool.

   
Со следующего шага мы начнем рассматривать деки.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий