Почему libc++'s vector: const reference не bool?

Раздел 23.3.7 Класс vector<bool> [вектор.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++.

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

1 ответов


мотивация для этого расширения, которое обнаруживается соответствующей программой и, следовательно, не соответствует, состоит в том, чтобы сделать vector<bool> ведите себя больше как vector<char> в отношении ссылок (const и в противном случае).

введение

С 1998 года, vector<bool> был высмеян как " не совсем контейнер."LWG 96, один из самых первых вопросов РГПВ, запустил дебаты. Сегодня, 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);
}

в стандартной спецификации говорится, что assert отмечен // Fires! вызовет, но только когда test С vector<bool>. При запуске с vector<char> (или vector кроме того bool когда соответствующий не-default T is назначено), тест проходит.

реализация libc++ стремилась свести к минимуму негативные последствия наличия vector<bool> вести себя по-разному в общем коде. Одна вещь, которую он сделал, чтобы достичь этого, - это сделать vector<T>::const_reference a прокси-ссылка, как указано 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 of vector и array.

существует несколько примеров функций C++11 и C++14, которые начинались как расширения в libc++. Вот как развиваются стандарты. Фактический продемонстрировал положительное полевой опыт оказывает сильное влияние. Люди стандартов-консервативная группа, когда дело доходит до изменения существующих спецификаций (как и должно быть). Угадывание, даже если вы уверены, что угадываете правильно, является рискованной стратегией для разработки международно признанного стандарта.