Раздел 23.3.7 Класс vector<bool>
[vector.bool], пункт 1 гласит:
template <class Allocator> class vector<bool, Allocator> {
public:
// types:
typedef bool const_reference;
...
Однако эта программа не компилируется при использовании libc ++:
#include <vector>
#include <type_traits>
int
main()
{
static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}
Кроме того, я отмечаю, что стандарт C ++ был последовательным в этой спецификации вплоть до C ++ 98. И еще я отмечу, что libc ++ последовательно не следовал этой спецификации с момента первого появления libc ++.
Какова мотивация для этого несоответствия?
Мотивация для этого расширения, которое можно обнаружить с помощью соответствующей программы и, следовательно, не соответствующей, заключается в vector<bool>
вести себя больше как vector<char>
в отношении ссылок (постоянных и других).
Вступление
С 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]); // Fires!
}
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
это к vector<bool>
(который должен быть переименован в bit_vector
— или что угодно), как array
это к vector
, И аналогия должна быть верной, независимо от того, говорим ли мы о bool
как value_type
из vector
а также array
,
Существует множество примеров функций C ++ 11 и C ++ 14, которые начинались как расширения в libc ++. Так развиваются стандарты. фактический продемонстрировал положительный Полевой опыт оказывает сильное влияние. Специалисты по стандартизации — консервативная группа, когда дело доходит до изменения существующих спецификаций (как и должно быть). Догадываться, даже если вы уверены, что правильно угадываете, — это рискованная стратегия для развития международно признанного стандарта.