В пункте 18 книги Скотта Мейерса « Эффективный STL: 50 конкретных способов улучшить использование стандартной библиотеки шаблонов» говорится, что следует избегать, vector <bool>
поскольку это не контейнер STL и на самом деле не содержит bool
s.
Следующий код:
vector <bool> v;
bool *pb =&v[0];
не будет компилироваться, нарушая требования контейнеров STL.
Ошибка:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector<T>::operator []
тип возврата должен быть T&
, но почему это особый случай vector<bool>
?
Из чего на vector<bool>
самом деле состоит?
Пункт далее говорит:
deque<bool> v; // is a STL container and it really contains bools
Можно ли это использовать как альтернативу vector<bool>
?
Кто-нибудь может объяснить это?
bool
, так как у элемента нет своего адреса.std::vector<bool> v;
скомпилирует.&v[0]
не будет (взяв временный адрес).vector<bool>
имеет плохую репутацию, но не совсем оправданно: isocpp.org/blog/2012/11/on-vectorboolОтветы:
По причинам оптимизации пространства стандарт C ++ (еще в C ++ 98) явно вызывается
vector<bool>
как специальный стандартный контейнер, где каждый bool использует только один бит пространства, а не один байт, как это сделал бы обычный bool (реализуя своего рода "динамический битовый набор"). В обмен на эту оптимизацию он не предлагает всех возможностей и интерфейса обычного стандартного контейнера.В этом случае, поскольку вы не можете взять адрес бита в байте, такие вещи, как
operator[]
не могут возвращать a,bool&
а вместо этого возвращают прокси-объект, который позволяет манипулировать конкретным рассматриваемым битом. Поскольку этот прокси-объект не является abool&
, вы не можете назначить его адрес так,bool*
как вы могли бы сделать это в результате вызова такого оператора в «нормальном» контейнере. В свою очередь, это означает, чтоbool *pb =&v[0];
это недействительный код.С другой стороны
deque
, такая специализация не вызывается, поэтому каждое bool принимает байт, и вы можете взять адрес возвращаемого значенияoperator[]
.Наконец, обратите внимание, что реализация стандартной библиотеки MS (возможно) субоптимальна в том смысле, что она использует небольшой размер блока для deques, а это означает, что использование deque в качестве замены не всегда является правильным ответом.
источник
std::array
это просто шаблонная оболочка вокруг необработанного массиваT[n]
с некоторыми вспомогательными функциями, такими какsize()
семантика копирования / перемещения и итераторами, добавленными, чтобы сделать его совместимым с STL - и (к счастью) он не нарушает свои собственные принципы (обратите внимание на мои скептицизм этих :) "специализируется" на "bool
".vector<bool>
содержит логические значения в сжатом виде, используя только один бит для значения (а не 8, как это делают массивы bool []). Невозможно вернуть ссылку на бит в С ++, поэтому существует специальный вспомогательный тип, «битовая ссылка», который предоставляет вам интерфейс для некоторого бита в памяти и позволяет вам использовать стандартные операторы и приведение типов.источник
deque<bool>
не является специализированным, так что это буквально просто deque, содержащий bools.vector<bool>
имеет конкретную реализацию шаблона. Я предполагаю, что другие контейнеры STL, такие какdeque<bool>
, не содержат, поэтому они содержат bool-ы, как и любые другие типы.Проблема заключается в том, что вместо истинной ссылки
vector<bool>
возвращается объект прокси-ссылки , поэтому код стиля C ++ 98bool * p = &v[0];
не компилируется. Однако современный C ++ 11auto p = &v[0];
можно заставить компилировать, если онoperator&
также возвращает объект-указатель прокси . Ховард Хиннант написал сообщение в блоге, в котором подробно описаны алгоритмические улучшения при использовании таких прокси-ссылок и указателей.У Скотта Мейерса есть длинный пункт 30 в « Более эффективном C ++» о прокси-классах. Вы можете пройти долгий путь, чтобы почти имитировать встроенные типы: для любого данного типа
T
пару прокси (например,reference_proxy<T>
иiterator_proxy<T>
) можно сделать взаимно согласованными в том смысле, чтоreference_proxy<T>::operator&()
иiterator_proxy<T>::operator*()
являются противоположными друг другу.Однако в какой-то момент нужно сопоставить прокси-объекты, чтобы они вели себя как
T*
илиT&
. Для прокси-итераторов можно перегрузить интерфейсoperator->()
шаблона и получить доступ к немуT
без повторной реализации всех функций. Однако для эталонных прокси вам потребуется перегрузкаoperator.()
, а это недопустимо в текущем C ++ (хотя Себастьян Редл представил такое предложение на BoostCon 2013). Вы можете выполнить подробный обходной путь, такой как.get()
член внутри ссылочного прокси, или реализовать весьT
интерфейс внутри ссылки (это то, что сделано дляvector<bool>::bit_reference
), но это приведет либо к потере встроенного синтаксиса, либо к введению пользовательских преобразований, не имеющих встроенной семантики для преобразований типов (вы можете иметь не более одного пользовательского преобразования для каждого аргумента).TL; DR : no
vector<bool>
- это не контейнер, потому что Стандарт требует реальной ссылки, но его можно заставить вести себя почти как контейнер, по крайней мере, намного ближе к C ++ 11 (авто), чем к C ++ 98.источник
Многие считают
vector<bool>
специализацию ошибкой.В статье «Устарение остатков библиотечных частей в C ++ 17»
есть предложение пересмотреть векторную частичную специализацию .
источник
Посмотрите, как это реализовано. STL в значительной степени строится на шаблонах, и поэтому заголовки содержат код, который они содержат.
например, посмотрите здесь реализацию stdc ++ .
Также интересно , даже если не СТЛ соответствующий битовый вектор является LLVM :: BitVector из здесь .
сущность
llvm::BitVector
- это вложенный класс, называемыйreference
и подходящая перегрузка оператора, чтобы сделатьBitVector
поведение аналогичнымvector
с некоторыми ограничениями. Приведенный ниже код представляет собой упрощенный интерфейс, показывающий, как BitVector скрывает класс, вызываемыйreference
для того, чтобы реальная реализация вела себя почти как реальный массив bool без использования 1 байта для каждого значения.class BitVector { public: class reference { reference &operator=(reference t); reference& operator=(bool t); operator bool() const; }; reference operator[](unsigned Idx); bool operator[](unsigned Idx) const; };
у этого кода есть приятные свойства:
BitVector b(10, false); // size 10, default false BitVector::reference &x = b[5]; // that's what really happens bool y = b[5]; // implicitly converted to bool assert(b[5] == false); // converted to bool assert(b[6] == b[7]); // bool operator==(const reference &, const reference &); b[5] = true; // assignment on reference assert(b[5] == true); // and actually it does work.
В этом коде действительно есть недостаток, попробуйте запустить:
std::for_each(&b[5], &b[6], some_func); // address of reference not an iterator
не будет работать, потому что
assert( (&b[5] - &b[3]) == (5 - 3) );
выйдет из строя (внутриllvm::BitVector
)это очень простая версия llvm.
std::vector<bool>
Также в нем есть рабочие итераторы. таким образом звонокfor(auto i = b.begin(), e = b.end(); i != e; ++i)
будет работать. а такжеstd::vector<bool>::const_iterator
.Однако все еще есть ограничения,
std::vector<bool>
которые заставляют его вести себя по-другому в некоторых случаях.источник
Это происходит с http://www.cplusplus.com/reference/vector/vector-bool/
источник