La motivación de esta extensión, que es detectable por un programa conforme, y por lo tanto no conforme, es hacer que se vector<bool>
comporte más vector<char>
con respecto a las referencias (const y de otro modo).
Introducción
Desde 1998, vector<bool>
ha sido ridiculizado como "no es un contenedor". LWG 96 , uno de los primeros temas de LWG, lanzó el debate. Hoy, 17 años después, vector<bool>
permanece prácticamente sin cambios.
Este artículo analiza algunos ejemplos específicos sobre cómo el comportamiento de vector<bool>
difiere de cualquier otra instanciación de vector
, perjudicando así el código genérico. Sin embargo, el mismo artículo analiza en detalle las excelentes propiedades de rendimiento que vector<bool>
pueden tener si se implementan correctamente.
Resumen : vector<bool>
no es un mal contenedor. De hecho, es bastante útil. Simplemente tiene mala fama.
De regreso const_reference
Como se presentó anteriormente y se detalla aquí , lo malo vector<bool>
es que se comporta de manera diferente en el código genérico que en otrosvector
instancias. Aquí hay un ejemplo 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 especificación estándar dice que la aserción marcada // Fires!
se activará, pero solo cuando test
se ejecute con un vector<bool>
. Cuando se ejecuta con un vector<char>
(o cualquiervector
además bool
cuando un no predeterminado apropiado T
es asignado), la prueba pasa.
La implementación de libc ++ buscó minimizar los efectos negativos de haberse vector<bool>
comportado de manera diferente en código genérico. Una cosa que hizo para lograr esto es hacer vector<T>::const_reference
una referencia de proxy , al igual que la especificadavector<T>::reference
, excepto que no se puede asignar a través de ella. Es decir, en libc ++, vector<T>::const_reference
es esencialmente un puntero al bit dentro de vector
, en lugar de una copia de ese bit.
En libc ++ lo anterior test
pasa para ambosvector<char>
y vector<bool>
.
¿A que costo?
La desventaja es que esta extensión es detectable, como se muestra en la pregunta. Sin embargo, muy pocos programas se preocupan por el tipo exacto de este alias y más programas se preocupan por el comportamiento.
¿Cuál es la motivación de esta no conformidad?
Para darle al cliente libc ++ un mejor comportamiento en código genérico, y quizás después de suficientes pruebas de campo, proponga esta extensión a un futuro estándar C ++ para el mejoramiento de toda la industria C ++.
Tal propuesta podría venir en forma de un nuevo contenedor (por ejemplo bit_vector
) que tenga la misma API que la actual vector<bool>
, pero con algunas actualizaciones como las que se const_reference
comentan aquí. Seguido de la desaprobación (y eventual eliminación) de la vector<bool>
especialización. bitset
También podría usar una pequeña actualización en este departamento, por ejemplo const_reference
, agregar y un conjunto de iteradores.
Es decir, en retrospectiva bitset
es a vector<bool>
(que debería cambiarse a bit_vector
- o lo que sea), como array
es a vector
. Y la analogía debería ser cierta ya sea que estemos hablando o no bool
como el value_type
de vector
y array
.
Hay varios ejemplos de características de C ++ 11 y C ++ 14 que comenzaron como extensiones en libc ++. Así es como evolucionan los estándares. La experiencia de campo positiva demostrada real tiene una gran influencia. La gente de los estándares es un grupo conservador cuando se trata de cambiar las especificaciones existentes (como debería ser). Adivinar, incluso cuando esté seguro de que está adivinando correctamente, es una estrategia arriesgada para desarrollar un estándar reconocido internacionalmente.
vector<bool>
una base más de primera clase?vector_bool<Alloc>
y anarray_bool<N>
para representar versiones empaquetadas (incluidos los iteradores de proxy de acceso aleatorio que iteran todos los bits) devector<bool, Alloc>
yarray<bool, N>
. Sin embargo,bitset<N>
(y su primoboost::dynamic_bitset<Alloc>
) representan una abstracción diferente: a saber, versiones empaquetadas destd::set<int>
. Así que me gustaría tener, digamos,bit_array<N>
ybit_vector<Alloc>
ser los sucesores de la franquicia del conjunto de bits, con iteradores bidireccionales apropiados (iterando sobre los 1 bits, en lugar de sobre todos los bits). ¿Qué piensas sobre esto?vector<bool>
un contenedor de acceso aleatorio conforme a std. No seríavector<bool>
una buena idea. :-) Estoy de acuerdo con Howard. Debería haberse llamado de otra forma.