Мотивация для этого расширения, которое может быть обнаружено соответствующей программой и, следовательно, не соответствует требованиям, состоит в том, чтобы заставить vector<bool>
вести себя как в vector<char>
отношении ссылок (const и в противном случае).
Введение
С 1998 года vector<bool>
его высмеивали как «не совсем контейнер». LWG 96 , одна из самых первых проблем LWG, инициировала дебаты. Сегодня, 17 лет спустя, vector<bool>
практически ничего не изменилось.
В этой статье приводятся некоторые конкретные примеры того, как поведение vector<bool>
отличается от любого другого экземпляра vector
, что наносит ущерб общему коду. Однако в той же статье подробно обсуждаются очень хорошие рабочие характеристики, которые vector<bool>
могут быть получены при правильной реализации.
Резюме : vector<bool>
неплохой контейнер. На самом деле это очень полезно. Просто у него плохая репутация.
Вернуться к const_reference
Как было сказано выше и подробно описано здесь , плохим vector<bool>
то, что он ведет себя в универсальном коде иначе, чем в других vector
экземплярах. Вот конкретный пример:
#include <cassert>
#include <vector>
template <class T>
void
test(std::vector<T>& v)
{
using const_ref = typename std::vector<T>::const_reference;
const std::vector<T>& cv = v;
const_ref cr = cv[0];
assert(cr == cv[0]);
v[0] = 1;
assert(true == cv[0]);
assert(cr == cv[0]);
}
int
main()
{
std::vector<char> vc(1);
test(vc);
std::vector<bool> vb(1);
test(vb);
}
Стандартная спецификация говорит, что отмеченное утверждение // Fires!
будет срабатывать, но только когда test
оно запускается с vector<bool>
. При запуске с vector<char>
(или любым vector
другим, bool
если назначено соответствующее значение, отличное от значения по умолчанию T
), тест проходит.
Реализация libc ++ стремилась свести к минимуму негативные последствия vector<bool>
различного поведения в общем коде. Единственное , что он сделал , чтобы добиться этого , чтобы сделать vector<T>::const_reference
на прокси-ссылки , так же , как указано vector<T>::reference
, за исключением того, что вы не можете назначить через него. То есть в libc ++ это, vector<T>::const_reference
по сути, указатель на бит внутри vector
, а не копия этого бита.
В libc ++ вышеуказанное test
подходит как для, так vector<char>
и для vector<bool>
.
Какой ценой?
Обратной стороной является то, что это расширение обнаружимо, как показано в вопросе. Однако очень немногие программы действительно заботятся о точном типе этого псевдонима, и больше программ заботятся о его поведении.
Какова мотивация этого несоответствия?
Чтобы улучшить поведение клиента libc ++ в общем коде и, возможно, после достаточного полевого тестирования, предложите это расширение для будущего стандарта C ++ для улучшения всей индустрии C ++.
Такое предложение могло бы появиться в форме нового контейнера (например bit_vector
), который будет иметь почти такой же API, как сегодняшний vector<bool>
, но с некоторыми обновлениями, такими как const_reference
обсуждаемые здесь. За этим следует прекращение поддержки (и возможное удаление) vector<bool>
специализации. bitset
также можно было бы использовать небольшое обновление в этом отделе, например, добавить const_reference
и набор итераторов.
То есть в ретроспективе bitset
это to vector<bool>
(которое следует переименовать в bit_vector
- или что-то еще), as array
is to vector
. И аналогия должна верны ли или нет , мы говорим о том, bool
как value_type
из vector
и array
.
Есть несколько примеров функций C ++ 11 и C ++ 14, которые начинались как расширения в libc ++. Так развиваются стандарты. Фактический продемонстрированный положительный полевой опыт оказывает сильное влияние. Специалисты по стандартам - консервативная группа, когда дело доходит до изменения существующих спецификаций (как и должно быть). Гадание, даже если вы уверены, что угадываете правильно, - рискованная стратегия для развития международно признанного стандарта.
vector<bool>
на более первоклассную основу?vector_bool<Alloc>
и anarray_bool<N>
для представления упакованных версий (включая итераторы прокси с произвольным доступом, повторяющие все биты)vector<bool, Alloc>
иarray<bool, N>
. Однакоbitset<N>
(и его двоюродный братboost::dynamic_bitset<Alloc>
) представляют собой другую абстракцию: а именно упакованные версииstd::set<int>
. Так что я хотел бы иметь, скажем,bit_array<N>
иbit_vector<Alloc>
быть преемниками франшизы битовых наборов, с соответствующими двунаправленными итераторами (итерация по 1-битам, а не по всем битам). Что вы думаете об этом?vector<bool>
создан контейнер произвольного доступа, соответствующий стандарту. Это неvector<bool>
лучшая идея. :-) Я согласен с Говардом. Его следовало назвать иначе.