A motivação para esta extensão, que é detectável por um programa em conformidade e, portanto, não conforme, é fazer com que o vector<bool>
comportamento seja mais semelhante vector<char>
em relação às referências (const e não).
Introdução
Desde 1998, vector<bool>
tem sido ridicularizado como "não exatamente um contêiner". O LWG 96 , um dos primeiros problemas do LWG, lançou o debate. Hoje, 17 anos depois, vector<bool>
permanece praticamente inalterado.
Este artigo apresenta alguns exemplos específicos de como o comportamento de vector<bool>
difere de todas as outras instanciações de vector
, prejudicando assim o código genérico. No entanto, o mesmo artigo discute detalhadamente as excelentes propriedades de desempenho que vector<bool>
podem ter se implementadas corretamente.
Resumo : vector<bool>
não é um recipiente ruim. Na verdade, é bastante útil. Ele só tem um nome ruim.
De volta a const_reference
Conforme apresentado acima e detalhado aqui , o que é ruim vector<bool>
é que ele se comporta de maneira diferente no código genérico do que em outras vector
instanciações. Aqui está um exemplo 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);
}
A especificação padrão diz que a declaração marcada // Fires!
será acionada, mas apenas quando test
for executada com um vector<bool>
. Quando executado com um vector<char>
(ou qualquer vector
além bool
quando um não-padrão apropriado T
é atribuído), o teste passa.
A implementação da libc ++ buscou minimizar os efeitos negativos de ter um vector<bool>
comportamento diferente no código genérico. Uma coisa que ele fez para conseguir isso foi fazer vector<T>::const_reference
uma referência de proxy , exatamente como o especificado vector<T>::reference
, exceto que você não pode atribuir por meio dele. Ou seja, no libc ++, vector<T>::const_reference
é essencialmente um ponteiro para o bit dentro do vector
, em vez de uma cópia desse bit.
Em libc ++, o acima test
passa para ambos vector<char>
e vector<bool>
.
A que custo?
A desvantagem é que essa extensão é detectável, conforme mostrado na pergunta. No entanto, poucos programas realmente se preocupam com o tipo exato desse alias e mais programas se preocupam com o comportamento.
Qual é a motivação para esta não conformidade?
Para dar ao cliente libc ++ um comportamento melhor em código genérico, e talvez depois de testes de campo suficientes, proponha esta extensão para um futuro padrão C ++ para o aprimoramento de toda a indústria C ++.
Essa proposta pode vir na forma de um novo contêiner (por exemplo bit_vector
) que tem praticamente a mesma API de hoje vector<bool>
, mas com algumas atualizações, como as const_reference
discutidas aqui. Seguido pela descontinuação (e eventual remoção) da vector<bool>
especialização. bitset
também poderia usar uma pequena atualização neste departamento, por exemplo const_reference
, adicionar e um conjunto de iteradores.
Ou seja, em retrospectiva bitset
é para vector<bool>
(que deve ser renomeado para bit_vector
- ou qualquer outra coisa), como array
é para vector
. E a analogia deve ser verdadeira, quer estejamos falando ou não sobre bool
como value_type
de vector
e array
.
Existem vários exemplos de recursos C ++ 11 e C ++ 14 que começaram como extensões em libc ++. É assim que os padrões evoluem. A experiência de campo positiva real demonstrada exerce forte influência. O pessoal dos padrões é um grupo conservador quando se trata de alterar as especificações existentes (como deveriam ser). Adivinhar, mesmo quando você tem certeza de que está adivinhando corretamente, é uma estratégia arriscada para desenvolver um padrão reconhecido internacionalmente.
vector<bool>
em uma base mais de primeira classe?vector_bool<Alloc>
e umarray_bool<N>
para representar versões compactadas (incluindo iteradores de proxy de acesso aleatório iterando todos os bits) devector<bool, Alloc>
earray<bool, N>
. No entanto,bitset<N>
(e seu primoboost::dynamic_bitset<Alloc>
) representam uma abstração diferente: a saber, versões compactadas destd::set<int>
. Portanto, gostaria de ter, digamos,bit_array<N>
ebit_vector<Alloc>
ser os sucessores da franquia de bitset, com iteradores bidirecionais apropriados (iterando sobre os bits de 1, em vez de sobre todos os bits). Quais são seus pensamentos sobre isso?vector<bool>
um contêiner de acesso aleatório em conformidade com o padrão. Não seriavector<bool>
uma boa ideia. :-) Eu concordo com Howard. Ele deveria ter sido chamado de outra coisa.