2015-06-20 6 views
2

Когда я перебираю vector<bool>, я обнаружил, что элементы, разыменованные через итератор, распознаются, как если бы они были const. Почему это? Измените либо контейнер, либо тип элемента, например list<bool>, или vector<short>, а элементы не являются константами. Этот код показывает, что я говорю о:Почему неконстантный вектор <bool> элементов const?

typedef bool T; 
#define C vector 
istringstream &operator>>(istringstream &iss, T &v) 
{ 
    cout << "non-const" << endl; 
    return iss; 
} 

istringstream &operator>>(istringstream &iss, const T &v) 
{ 
    cout << "const" << endl; 
    return iss; 
} 

istringstream &operator>>(istringstream &iss, C<T> &c) 
{ 
    for (C<T>::iterator it = c.begin(); it != c.end(); ++it) 
    { 
     iss >> *it; 
    } 
    return iss; 
} 

int main() 
{ 
    C<T> c(1); 
    istringstream iss("1"); 
    iss >> c; 
} 

Для vector<bool>, программа печатает «сопзЬ» в консоли. Измените typedef и константу манифеста в верхней части на что-либо, кроме этих двух комбинаций, и печатает «неконстантные». Кроме того, если я заменю строку, iss >> *it, с T v; iss >> v; *it = v;, она работает как ожидалось - все комбинации печатают «неконстантные».

Я вижу то же поведение с GCC 4.1.2 C++ 98 (через codepad.org) и VS2015 C++ 14 + (?).

+1

Короткий ответ: 'std :: vector ' специальный. Вы можете найти ссылку на нее, чтобы увидеть, что отличает. – chris

+0

Да, я только что заметил это. Я пишу несколько модных шаблонов, и я бы предпочел не специализироваться на bool. – plong

+0

Прочтите некоторые интересные факты о 'vector ' здесь: https://isocpp.org/blog/2012/11/on-vectorbool – Steephen

ответ

6

Несмотря на название, vector<bool> не содержит bool s, и разыменование его итератора не дает вам bool&. Вместо этого он дает вам объект типа vector<bool>::reference, который пытается имитировать поведение bool& как можно больше.

Невозможно преобразовать vector<bool>::reference в bool&, поэтому непостоянная перегрузка не работает. vector<bool>::reference, однако, можно преобразовать в bool, который затем может привязываться к const bool&.

2

std::vector<bool> - это специализация std::vector, которая выполняет динамический битрейт с пространственным коэффициентом. Итераторы вернулись с begin(), а end() фактически указывают объекты класса прокси-класса, представляющие логические значения.

Ссылки, возвращенные из разыменования итераторов, являются значениями класса типа, а не фактическими булевыми. Он преобразуется в значение bool, поэтому перегрузка, ссылающаяся на константу, переписывается (rvalues ​​могут связываться со ссылками на const).

+0

Спасибо, Крис, T.C. и 0x499602D2. Что объясняет его. Принимая совет Криса, я нашел [хорошую статью] (http: //www.gotw.са/публикации/mill09.htm). – plong

5

Для сохранения памяти vector<bool> не является фактическим массивом bool. Для значения bool требуется только бит для хранения, но минимальный размер может быть 1byte = 8 бит. Поэтому, не используя тривиальную реализацию, вы можете иметь в 8 раз более эффективное хранилище (насколько это касается памяти), что бы обеспечить простой массив bool.

Однако, следствием является то, что элемент vector<bool> не BOOL, но vector<bool>::reference, который почти, но не совсем такой же, как bool&. Большинство операций здесь, но некоторые из них не (как |= для Exemple)

Тем не менее вы можете преобразовать его в bool или инициализировать новый объект const bool с ним ... и делать все, что вам, что с помощью этого нового объекта