L'article 18 du livre de Scott Meyers Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library dit d'éviter vector <bool>
car ce n'est pas un conteneur STL et il ne contient pas vraiment de bool
s.
Le code suivant:
vector <bool> v;
bool *pb =&v[0];
ne compilera pas, violant une exigence des conteneurs STL.
Erreur:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector<T>::operator []
le type de retour est censé être T&
, mais pourquoi est-ce un cas particulier vector<bool>
?
En quoi vector<bool>
consiste vraiment?
L'article dit en outre:
deque<bool> v; // is a STL container and it really contains bools
Cela peut-il être utilisé comme alternative à vector<bool>
?
Quelqu'un peut-il expliquer cela?
bool
, puisque l'élément n'a pas sa propre adresse.std::vector<bool> v;
compilera.&v[0]
ne sera pas (en prenant l'adresse d'un temporaire).vector<bool>
a une mauvaise réputation mais pas tout à fait à juste titre: isocpp.org/blog/2012/11/on-vectorboolRéponses:
Pour des raisons d'optimisation de l'espace, le standard C ++ (aussi loin que C ++ 98) appelle explicitement
vector<bool>
un conteneur standard spécial où chaque booléen n'utilise qu'un bit d'espace plutôt qu'un octet comme le ferait un bool normal (implémentation d'une sorte de "jeu de bits dynamique"). En échange de cette optimisation, il n'offre pas toutes les capacités et l'interface d'un conteneur standard normal.Dans ce cas, puisque vous ne pouvez pas prendre l'adresse d'un bit dans un octet, des choses telles que
operator[]
ne peuvent pas retourner unbool&
mais à la place renvoient un objet proxy qui permet de manipuler le bit particulier en question. Puisque cet objet proxy n'est pas unbool&
, vous ne pouvez pas attribuer son adresse à unbool*
comme vous le pourriez avec le résultat d'un tel appel d'opérateur sur un conteneur "normal". À son tour, cela signifie que cebool *pb =&v[0];
n'est pas un code valide.D'un autre côté,
deque
aucune spécialisation de ce type n'est appelée, donc chaque booléen prend un octet et vous pouvez prendre l'adresse de la valeur renvoyéeoperator[]
.Enfin, notez que l'implémentation de la bibliothèque standard MS est (sans doute) sous-optimale en ce qu'elle utilise une petite taille de bloc pour les deques, ce qui signifie que l'utilisation de deque comme substitut n'est pas toujours la bonne réponse.
la source
std::array
est simplement un wrapper basé sur un modèle autour d'un tableau brut deT[n]
avec quelques fonctions d'aide commesize()
, copier / déplacer la sémantique, et des itérateurs ajoutés pour le rendre compatible STL - et (heureusement) il ne viole pas ses propres principes pour (notez mon scepticisme de ceux-ci :) 'se spécialiser' pour 'bool
'.vector<bool>
contient des valeurs booléennes sous forme compressée en n'utilisant qu'un seul bit pour value (et non 8 comme le font les tableaux bool []). Il n'est pas possible de renvoyer une référence à un bit en c ++, il existe donc un type d'aide spécial, "bit reference", qui vous fournit une interface vers un bit en mémoire et vous permet d'utiliser des opérateurs et des transtypages standard.la source
deque<bool>
n'est pas spécialisé, donc c'est littéralement juste un deque contenant des booléens.vector<bool>
a une implémentation de modèle spécifique. Je suppose que d'autres conteneurs STL, tels quedeque<bool>
, ne le font pas, donc ils contiennent des booléens comme tous les autres types.Le problème est que
vector<bool>
renvoie un objet de référence proxy au lieu d'une vraie référence, de sorte que le code de style C ++ 98bool * p = &v[0];
ne se compile pas. Cependant, le C ++ 11 moderne avecauto p = &v[0];
peut être fait pour compiler s'il renvoieoperator&
également un objet pointeur proxy . Howard Hinnant a écrit un article de blog détaillant les améliorations algorithmiques lors de l'utilisation de ces références et pointeurs proxy.Scott Meyers a un long Item 30 dans More Effective C ++ sur les classes proxy. Vous pouvez faire un long chemin pour imiter presque les types intégrés: pour tout type donné
T
, une paire de proxies (par exemplereference_proxy<T>
etiterator_proxy<T>
) peut être rendue mutuellement cohérente dans le sens oùreference_proxy<T>::operator&()
etiterator_proxy<T>::operator*()
sont l'inverse de l'autre.Cependant, à un moment donné, il faut mapper les objets proxy pour qu'ils se comportent comme
T*
ouT&
. Pour les proxies d'itérateur, on peut surchargeroperator->()
et accéder à l'T
interface du modèle sans réimplémenter toutes les fonctionnalités. Cependant, pour les proxys de référence, vous auriez besoin d'une surchargeoperator.()
, ce qui n'est pas autorisé dans le C ++ actuel (bien que Sebastian Redl ait présenté une telle proposition sur BoostCon 2013). Vous pouvez faire un contournement détaillé comme un.get()
membre à l'intérieur du proxy de référence, ou implémenter touteT
l'interface de dans la référence (c'est ce qui est fait pourvector<bool>::bit_reference
), mais cela perdra la syntaxe intégrée ou introduira des conversions définies par l'utilisateur qui n'ont pas de sémantique intégrée pour les conversions de type (vous pouvez avoir au plus une conversion définie par l'utilisateur par argument).TL; DR : no
vector<bool>
n'est pas un conteneur car le Standard nécessite une vraie référence, mais il peut être fait pour se comporter presque comme un conteneur, au moins beaucoup plus proche avec C ++ 11 (auto) qu'en C ++ 98.la source
Beaucoup considèrent la
vector<bool>
spécialisation comme une erreur.Dans un article "Deprecating Vestigial Library Parts in C ++ 17",
il y a une proposition de reconsidérer la spécialisation partielle vectorielle .
la source
Regardez comment il est mis en œuvre. la STL s'appuie largement sur des modèles et, par conséquent, les en-têtes contiennent le code qu'ils contiennent.
par exemple regarder à l' stdc ++ mise en œuvre ici .
également intéressant, même si ce n'est pas un vecteur de bits conforme stl, est le llvm :: BitVector d' ici .
L'essence de la
llvm::BitVector
est une classe imbriquée appeléereference
et une surcharge d'opérateur appropriée pour rendre leBitVector
comportement similaire àvector
avec certaines limitations. Le code ci-dessous est une interface simplifiée pour montrer comment BitVector cache une classe appeléereference
pour que l'implémentation réelle se comporte presque comme un vrai tableau de booléens sans utiliser 1 octet pour chaque valeur.ce code a ici les belles propriétés:
Ce code a en fait un défaut, essayez d'exécuter:
ne fonctionnera pas car
assert( (&b[5] - &b[3]) == (5 - 3) );
échouera (à l'intérieurllvm::BitVector
)c'est la version llvm très simple.
std::vector<bool>
contient également des itérateurs fonctionnels. ainsi l'appelfor(auto i = b.begin(), e = b.end(); i != e; ++i)
fonctionnera. et aussistd::vector<bool>::const_iterator
.Cependant, il y a encore des limites
std::vector<bool>
qui font qu'il se comporte différemment dans certains cas.la source
Cela vient de http://www.cplusplus.com/reference/vector/vector-bool/
la source