El artículo 18 del libro de Scott Meyers Effective STL: 50 Specific Ways to Mejorar el uso de la biblioteca de plantillas estándar dice que se debe evitar, vector <bool>
ya que no es un contenedor STL y en realidad no contiene bool
s.
El siguiente código:
vector <bool> v;
bool *pb =&v[0];
no compilará, violando un requisito de los contenedores STL.
Error:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector<T>::operator []
Se supone que el tipo de retorno es T&
, pero ¿por qué es un caso especial para vector<bool>
?
¿En qué vector<bool>
consiste realmente?
El artículo dice además:
deque<bool> v; // is a STL container and it really contains bools
¿Se puede utilizar como alternativa a vector<bool>
?
¿Alguien puede explicar esto?
bool
, ya que el elemento no tiene su propia dirección.std::vector<bool> v;
se compilará.&v[0]
no lo hará (tomando dirección de un temporal).vector<bool>
tiene una mala reputación pero no del todo justificable, por lo que: isocpp.org/blog/2012/11/on-vectorboolRespuestas:
Por razones de optimización del espacio, el estándar C ++ (desde C ++ 98) llama explícitamente
vector<bool>
como un contenedor estándar especial donde cada bool usa solo un bit de espacio en lugar de un byte como lo haría un bool normal (implementando una especie de "conjunto de bits dinámico"). A cambio de esta optimización, no ofrece todas las capacidades e interfaz de un contenedor estándar normal.En este caso, dado que no puede tomar la dirección de un bit dentro de un byte, cosas como
operator[]
no pueden devolver un,bool&
sino devolver un objeto proxy que permite manipular el bit en particular en cuestión. Dado que este objeto proxy no es unbool&
, no puede asignar su dirección a unabool*
como podría hacerlo con el resultado de dicha llamada de operador en un contenedor "normal". A su vez, esto significa quebool *pb =&v[0];
no es un código válido.Por otro lado
deque
, no tiene ninguna especialización de este tipo, por lo que cada bool toma un byte y puede tomar la dirección del valor devueltooperator[]
.Finalmente, tenga en cuenta que la implementación de la biblioteca estándar de MS es (posiblemente) subóptima ya que usa un tamaño de fragmento pequeño para deques, lo que significa que usar deque como sustituto no siempre es la respuesta correcta.
fuente
std::array
es simplemente un envoltorio con plantilla alrededor de una matriz sin procesarT[n]
con algunas funciones auxiliares comosize()
, copiar / mover semántica e iteradores agregados para hacerlo compatible con STL, y (afortunadamente) no viola sus propios principios para (tenga en cuenta mi escepticismo de estos :) 'especializarse' para 'bool
'.vector<bool>
contiene valores booleanos en forma comprimida usando solo un bit por valor (y no 8 como lo hacen las matrices bool []). No es posible devolver una referencia a un bit en c ++, por lo que hay un tipo de ayuda especial, "referencia de bit", que le proporciona una interfaz para algún bit en la memoria y le permite utilizar operadores y conversiones estándar.fuente
deque<bool>
no está especializado, por lo que es literalmente solo un deque con bools.vector<bool>
tiene una implementación de plantilla específica. Supongo que otros contenedores STL, comodeque<bool>
no, contienen bool-s como cualquier otro tipo.El problema es que
vector<bool>
devuelve un objeto de referencia de proxy en lugar de una referencia verdadera, por lo que el código de estilo C ++ 98bool * p = &v[0];
no se compilará. Sin embargo, el C ++ 11 modernoauto p = &v[0];
se puede compilar sioperator&
también devuelve un objeto de puntero proxy . Howard Hinnant ha escrito una publicación de blog que detalla las mejoras algorítmicas al usar tales referencias y punteros de proxy.Scott Meyers tiene un artículo 30 extenso en C ++ más efectivo sobre clases de proxy. Puede recorrer un largo camino para casi imitar los tipos incorporados: para cualquier tipo dado
T
, un par de proxies (por ejemplo,reference_proxy<T>
yiterator_proxy<T>
) se pueden hacer mutuamente consistentes en el sentido de quereference_proxy<T>::operator&()
yiterator_proxy<T>::operator*()
son inversos entre sí.Sin embargo, en algún momento es necesario volver a mapear los objetos proxy para que se comporten como
T*
oT&
. Para los proxies de iterador, se puede sobrecargaroperator->()
y acceder a laT
interfaz de la plantilla sin volver a implementar toda la funcionalidad. Sin embargo, para los proxies de referencia, necesitaría sobrecargaroperator.()
, y eso no está permitido en C ++ actual (aunque Sebastian Redl presentó dicha propuesta en BoostCon 2013). Puede hacer una solución detallada como un.get()
miembro dentro del proxy de referencia, o implementar todaT
la interfaz dentro de la referencia (esto es lo que se hace paravector<bool>::bit_reference
), pero esto perderá la sintaxis incorporada o introducirá conversiones definidas por el usuario que no tienen semántica incorporada para las conversiones de tipos (puede tener como máximo una conversión definida por el usuario por argumento).TL; DR : no
vector<bool>
no es un contenedor porque el Estándar requiere una referencia real, pero se puede hacer que se comporte casi como un contenedor, al menos mucho más cerca con C ++ 11 (auto) que en C ++ 98.fuente
Muchos consideran que la
vector<bool>
especialización es un error.En un documento "Deprecating Vestigial Library Parts in C ++ 17"
hay una propuesta para reconsiderar la especialización parcial vectorial .
fuente
Mira cómo se implementa. el STL se basa en gran medida en plantillas y, por lo tanto, los encabezados contienen el código que contienen.
por ejemplo, mire la implementación de stdc ++ aquí .
También es interesante, aunque no es un vector de bits conforme a stl, el llvm :: BitVector de aquí .
la esencia de
llvm::BitVector
es una clase anidada llamadareference
y una sobrecarga de operador adecuada para hacer que elBitVector
comportamiento sea similarvector
con algunas limitaciones. El siguiente código es una interfaz simplificada para mostrar cómo BitVector oculta una clase llamadareference
para hacer que la implementación real se comporte casi como una matriz real de bool sin usar 1 byte para cada valor.este código aquí tiene las buenas propiedades:
Este código en realidad tiene una falla, intente ejecutar:
no funcionará porque
assert( (&b[5] - &b[3]) == (5 - 3) );
fallará (dentrollvm::BitVector
)esta es la versión llvm muy simple.
std::vector<bool>
también tiene iteradores de trabajo. así la llamadafor(auto i = b.begin(), e = b.end(); i != e; ++i)
funcionará. y tambiénstd::vector<bool>::const_iterator
.Sin embargo, todavía existen limitaciones
std::vector<bool>
que hacen que se comporte de manera diferente en algunos casos.fuente
Esto proviene de http://www.cplusplus.com/reference/vector/vector-bool/
fuente