O item 18 do livro de Scott Meyers STL eficaz: 50 maneiras específicas de melhorar seu uso da biblioteca de modelos padrão diz para evitar, vector <bool>
pois não é um contêiner STL e realmente não contém bool
s.
O seguinte código:
vector <bool> v;
bool *pb =&v[0];
não irá compilar, violando um requisito de contêineres STL.
Erro:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector<T>::operator []
O tipo de retorno deveria ser T&
, mas por que é um caso especial vector<bool>
?
Em que vector<bool>
realmente consiste?
O item diz ainda:
deque<bool> v; // is a STL container and it really contains bools
Isso pode ser usado como uma alternativa para vector<bool>
?
Alguém pode explicar isso?
bool
, já que o elemento não tem seu próprio endereço.std::vector<bool> v;
irá compilar.&v[0]
não (levando endereço de um temporário).vector<bool>
tem uma má reputação, mas não totalmente justificável: isocpp.org/blog/2012/11/on-vectorboolRespostas:
Por motivos de otimização de espaço, o padrão C ++ (já em C ++ 98) chama explicitamente
vector<bool>
como um contêiner padrão especial onde cada bool usa apenas um bit de espaço em vez de um byte como um bool normal faria (implementando uma espécie de "bitset dinâmico"). Em troca dessa otimização, ele não oferece todos os recursos e interface de um contêiner padrão normal.Nesse caso, como você não pode obter o endereço de um bit dentro de um byte, coisas como
operator[]
não podem retornar um,bool&
mas em vez disso, retornam um objeto proxy que permite manipular o bit específico em questão. Como esse objeto proxy não é umbool&
, você não pode atribuir seu endereço a umbool*
como faria com o resultado de uma chamada de operador em um contêiner "normal". Por sua vez, isso significa que essebool *pb =&v[0];
código não é válido.Por outro lado
deque
, não há nenhuma especialização chamada, então cada bool leva um byte e você pode pegar o endereço do valor de retornooperator[]
.Finalmente, observe que a implementação da biblioteca padrão MS é (discutivelmente) subótima, pois usa um pequeno tamanho de bloco para deques, o que significa que usar deque como substituto nem sempre é a resposta certa.
fonte
std::array
é meramente um invólucro modelado em torno de uma matriz bruta deT[n]
com algumas funções auxiliares comosize()
copiar / mover semântica e iteradores adicionados para torná-lo compatível com STL - e (felizmente) não viola seus próprios princípios para (observe meu ceticismo em relação a estes :) 'especializar-se' para 'bool
'.vector<bool>
contém valores booleanos na forma compactada usando apenas um bit para valor (e não 8 como os arrays bool [] fazem). Não é possível retornar uma referência a um bit em c ++, portanto, há um tipo auxiliar especial, "referência de bit", que fornece uma interface para algum bit na memória e permite o uso de operadores e conversões padrão.fonte
deque<bool>
não é especializado, então é literalmente apenas um deque segurando bools.vector<bool>
tem uma implementação de template específica. Eu acho que outros contêineres STL, comodeque<bool>
não, então eles contêm bool-s como qualquer outro tipo.O problema é que
vector<bool>
retorna um objeto de referência de proxy em vez de uma referência verdadeira, de modo que o código de estilo C ++ 98bool * p = &v[0];
não compila. No entanto, o C ++ 11 moderno comauto p = &v[0];
pode ser feito para compilar seoperator&
também retornar um objeto de ponteiro de proxy . Howard Hinnant escreveu uma postagem no blog detalhando as melhorias algorítmicas ao usar tais referências de proxy e ponteiros.Scott Meyers tem um longo Item 30 em C ++ Mais Eficaz sobre classes de proxy. Você pode percorrer um longo caminho para quase imitar os tipos embutidos: para qualquer tipo
T
, um par de proxies (por exemplo,reference_proxy<T>
eiterator_proxy<T>
) pode ser mutuamente consistente no sentido de quereference_proxy<T>::operator&()
eiterator_proxy<T>::operator*()
são inversos um do outro.No entanto, em algum ponto, é necessário mapear os objetos proxy de volta para se comportarem como
T*
ouT&
. Para proxies iteradores, pode-se sobrecarregaroperator->()
e acessar aT
interface do template sem reimplementar todas as funcionalidades. No entanto, para proxies de referência, você precisaria sobrecarregaroperator.()
, e isso não é permitido no C ++ atual (embora Sebastian Redl tenha apresentado tal proposta no BoostCon 2013). Você pode fazer uma solução alternativa detalhada como um.get()
membro dentro do proxy de referência, ou implementar todaT
a interface de dentro da referência (isto é o que é feito paravector<bool>::bit_reference
), mas isso perderá a sintaxe interna ou introduzirá conversões definidas pelo usuário que não têm semântica interna para conversões de tipo (você pode ter no máximo uma conversão definida pelo usuário por argumento).TL; DR : não
vector<bool>
não é um contêiner porque o Padrão requer uma referência real, mas pode ser feito para se comportar quase como um contêiner, pelo menos muito mais próximo do C ++ 11 (automático) do que do C ++ 98.fonte
Muitos consideram a
vector<bool>
especialização um erro.Em um artigo "Desprezando partes da biblioteca vestigial em C ++ 17"
há uma proposta para reconsiderar a especialização parcial do vetor .
fonte
Veja como isso é implementado. a STL se baseia amplamente em modelos e, portanto, os cabeçalhos contêm o código que eles contêm.
por exemplo, veja a implementação stdc ++ aqui .
Também interessante, embora não um stl conformidade vetor de bits é o llvm :: BitVector a partir daqui .
a essência do
llvm::BitVector
é uma classe aninhada chamadareference
e uma sobrecarga de operador adequada para tornar oBitVector
comportamento semelhante a,vector
com algumas limitações. O código a seguir é uma interface simplificada para mostrar como o BitVector oculta uma classe chamadareference
para fazer a implementação real quase se comportar como um array real de bool sem usar 1 byte para cada valor.este código aqui tem as boas propriedades:
Este código realmente tem uma falha, tente executar:
não funcionará porque
assert( (&b[5] - &b[3]) == (5 - 3) );
falhará (dentrollvm::BitVector
)esta é a versão llvm muito simples.
std::vector<bool>
também tem iteradores funcionais. assim, a chamadafor(auto i = b.begin(), e = b.end(); i != e; ++i)
funcionará. e tambémstd::vector<bool>::const_iterator
.No entanto, ainda existem limitações
std::vector<bool>
que o fazem se comportar de forma diferente em alguns casos.fonte
Isso vem de http://www.cplusplus.com/reference/vector/vector-bool/
fonte