La motivazione di questa estensione, che è rilevabile da un programma conforme, e quindi non conforme, è quella di far vector<bool>
comportarsi più comevector<char>
rispetto ai riferimenti (const e non).
introduzione
Dal 1998, vector<bool>
è stato deriso come "non proprio un contenitore". LWG 96 , una delle primissime questioni LWG, ha lanciato il dibattito. Oggi, 17 anni dopo, vector<bool>
rimane sostanzialmente invariato.
Questo documento entra in alcuni esempi specifici su come il comportamento di vector<bool>
differisce da ogni altra istanziazione di vector
, danneggiando così il codice generico. Tuttavia lo stesso articolo discute a lungo le proprietà di prestazione molto bellevector<bool>
possono avere se implementate correttamente.
Riepilogo : vector<bool>
non è un cattivo contenitore. In realtà è abbastanza utile. Ha solo un brutto nome.
Torna a const_reference
Come introdotto sopra e descritto in dettaglio qui , ciò che è negativo vector<bool>
è che si comporta in modo diverso nel codice generico rispetto ad altre vector
istanze. Ecco un esempio concreto:
#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);
}
La specifica standard dice che l'assert contrassegnato // Fires!
si attiverà, ma solo quando test
viene eseguito con a vector<bool>
. Quando viene eseguito con un vector<char>
(o qualsiasi vector
altro bool
quando T
viene assegnato un valore non predefinito appropriato ), il test viene superato.
L'implementazione di libc ++ ha cercato di minimizzare gli effetti negativi di un vector<bool>
comportamento diverso nel codice generico. Una cosa che ha fatto per ottenere ciò è stata creare vector<T>::const_reference
un riferimento proxy , proprio come specificato vector<T>::reference
, tranne per il fatto che non è possibile assegnare tramite esso. Cioè, su libc ++, vector<T>::const_reference
è essenzialmente un puntatore al bit all'interno di vector
, invece di una copia di quel bit.
Su libc ++ quanto sopra test
passa per entrambi vector<char>
e vector<bool>
.
A che costo?
Lo svantaggio è che questa estensione è rilevabile, come mostrato nella domanda. Tuttavia, pochissimi programmi si preoccupano effettivamente del tipo esatto di questo alias e più programmi si preoccupano del comportamento.
Qual è la motivazione di questa non conformità?
Per dare al client libc ++ un comportamento migliore nel codice generico, e forse dopo sufficienti test sul campo, proporre questa estensione a un futuro standard C ++ per il miglioramento dell'intero settore C ++.
Una tale proposta potrebbe presentarsi sotto forma di un nuovo contenitore (ad esempio bit_vector
) che ha più o meno la stessa API di oggi vector<bool>
, ma con alcuni aggiornamenti come quello const_reference
discusso qui. Seguito dalla deprecazione (ed eventuale rimozione) della vector<bool>
specializzazione. bitset
potrebbe anche utilizzare un piccolo aggiornamento in questo reparto, ad esempio add const_reference
, e una serie di iteratori.
Cioè, col senno di poi bitset
è a vector<bool>
(che dovrebbe essere rinominato in bit_vector
- o qualsiasi altra cosa), così come array
è vector
. E l'analogia dovrebbe valere anche se non stiamo parlando bool
come value_type
di vector
ed array
.
Ci sono diversi esempi di funzionalità di C ++ 11 e C ++ 14 che sono iniziate come estensioni in libc ++. È così che si evolvono gli standard. L'effettiva esperienza sul campo positiva dimostrata ha una forte influenza. La gente degli standard è un gruppo conservatore quando si tratta di modificare le specifiche esistenti (come dovrebbero essere). Indovinare, anche quando sei sicuro di indovinare correttamente, è una strategia rischiosa per sviluppare uno standard riconosciuto a livello internazionale.
vector<bool>
su una base più di prima classe?