Motywacją do tego rozszerzenia, które jest wykrywalne przez zgodny program, a zatem niezgodne, jest sprawienie, aby vector<bool>zachowywały się bardziej jakvector<char> w odniesieniu do odniesień (stałych i innych).
Wprowadzenie
Od 1998 roku vector<bool>był wyśmiewany jako „niezupełnie pojemnik”. LWG 96 , jeden z pierwszych numerów LWG, zapoczątkował debatę. Dziś, 17 lat później, vector<bool>pozostaje w dużej mierze niezmieniony.
W tym artykule przedstawiono kilka konkretnych przykładów, w jaki sposób zachowanie vector<bool>różni się od wszystkich innych instancji programu vector, szkodząc w ten sposób kodowi ogólnemu. Jednak ten sam artykuł szczegółowo omawia bardzo dobre właściwości vector<bool>użytkowe, jeśli są odpowiednio wdrożone.
Podsumowanie : vector<bool>nie jest to zły pojemnik. Właściwie to jest całkiem przydatne. Po prostu ma złe imię.
Wrócić do const_reference
Jak przedstawiono powyżej i szczegółowo omówiono tutaj , wadą jest vector<bool>to, że w kodzie ogólnym zachowuje się inaczej niż inne vectorinstancje. Oto konkretny przykład:
#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]);
}
int
main()
{
std::vector<char> vc(1);
test(vc);
std::vector<bool> vb(1);
test(vb);
}
Standardowa specyfikacja mówi, że zaznaczone potwierdzenie // Fires!zostanie wyzwolone, ale tylko wtedy, gdy testzostanie uruchomione z rozszerzeniem vector<bool>. Po uruchomieniu z vector<char>(lub dowolny vectoroprócz boolgdy odpowiednie non-defaultT przypisano ), test przechodzi.
Implementacja libc ++ starała się zminimalizować negatywne skutki vector<bool>odmiennego zachowania w kodzie ogólnym. Jedna rzecz to robiło do osiągnięcia tego celu jest, aby vector<T>::const_referencedo proxy odniesienia , podobnie jak podano vector<T>::reference, oprócz tego, że nie można przypisać jego pośrednictwem. Oznacza to, że w libc ++ vector<T>::const_referencejest zasadniczo wskaźnikiem do bitu wewnątrzvector , zamiast kopii tego bitu.
W libc ++ powyższe działa testzarówno dla, jak vector<char>i vector<bool>.
Jakim kosztem?
Wadą jest to, że to rozszerzenie jest wykrywalne, jak pokazano w pytaniu. Jednak bardzo niewiele programów faktycznie dba o dokładny typ tego aliasu, a więcej programów przejmuje się zachowaniem.
Jaka jest przyczyna tego braku zgodności?
Aby zapewnić klientowi libc ++ lepsze zachowanie w kodzie ogólnym i być może po wystarczających testach w terenie, zaproponuj to rozszerzenie do przyszłego standardu C ++ w celu ulepszenia całej branży C ++.
Taka propozycja może przyjść w postaci nowego kontenera (np. bit_vector), Który ma prawie takie samo API jak dzisiejsze vector<bool>, ale z kilkoma aktualizacjami, takimi jak const_referenceomówione tutaj. Następnie wycofanie (i ostateczne usunięcie) vector<bool>specjalizacji. bitsetprzydałoby się też trochę aktualizacji w tym dziale, np. dodawanie const_referencei zestaw iteratorów.
Oznacza to, że z perspektywy czasu bitsetjest to vector<bool>(co powinno zostać przemianowane na bit_vector- lub cokolwiek innego), tak jak arrayjest vector. A analogia powinna uznać za prawdziwe, czy nie mówimy booljak value_typeo vectoriarray .
Istnieje wiele przykładów funkcji C ++ 11 i C ++ 14, które zaczęły się jako rozszerzenia w libc ++. Tak ewoluują standardy. Faktycznie wykazane pozytywne doświadczenia terenowe mają silny wpływ. Standardowcy to konserwatywna grupa, jeśli chodzi o zmianę istniejących specyfikacji (tak, jak powinny). Zgadywanie, nawet jeśli masz pewność, że zgadujesz poprawnie, jest ryzykowną strategią ewolucji międzynarodowego standardu.
vector<bool>na bardziej pierwszorzędny charakter?