Мотивація цього розширення, яке виявляється відповідною програмою і, отже, невідповідним, полягає в тому, щоб зробити 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]); // 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
також може використовувати невелике оновлення в цьому відділі, наприклад, add const_reference
та набір ітераторів.
Тобто, заднім числом bitset
є vector<bool>
(що має бути перейменовано на bit_vector
- або що завгодно), як array
і vector
. І аналогія повинна бути правдивою, незалежно від того, чи ми говоримо bool
як value_type
про vector
і array
.
Існує кілька прикладів функцій C ++ 11 та C ++ 14, які розпочались як розширення в libc ++. Так розвиваються стандарти. Фактичний продемонстрований позитивний досвід на місцях має сильний вплив. Що стосується зміни існуючих специфікацій (як це повинно бути), люди, що працюють за стандартами, - це консервативна група. Відгадування, навіть коли ви впевнені, що вгадуєте правильно, є ризикованою стратегією розвитку міжнародно визнаного стандарту.
vector<bool>
на більш першокласні основи?