Почему вектор & lt; bool & gt; :: const_reference в libc ++ не является bool?

Раздел 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 ++.

Какова мотивация для этого несоответствия?

89

Решение

Мотивация для этого расширения, которое можно обнаружить с помощью соответствующей программы и, следовательно, не соответствующей, заключается в 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 ++. Так развиваются стандарты. фактический продемонстрировал положительный Полевой опыт оказывает сильное влияние. Специалисты по стандартизации — консервативная группа, когда дело доходит до изменения существующих спецификаций (как и должно быть). Догадываться, даже если вы уверены, что правильно угадываете, — это рискованная стратегия для развития международно признанного стандарта.

96

Другие решения


По вопросам рекламы [email protected]