Punkt 18 von Scott Meyers 'Buch Effective STL: 50 Spezifische Möglichkeiten zur Verbesserung Ihrer Verwendung der Standardvorlagenbibliothek sollten vermieden werden , vector <bool>
da es sich nicht um einen STL-Container handelt und nicht wirklich bool
s enthält.
Der folgende Code:
vector <bool> v;
bool *pb =&v[0];
wird nicht kompiliert, was eine Anforderung von STL-Containern verletzt.
Error:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector<T>::operator []
Rückgabetyp soll sein T&
, aber warum ist es ein Sonderfall für vector<bool>
?
Woraus besteht vector<bool>
eigentlich?
Der Artikel sagt weiter:
deque<bool> v; // is a STL container and it really contains bools
Kann dies als Alternative zu verwendet werden vector<bool>
?
Kann das bitte jemand erklären?
bool
, da das Element keine eigene Adresse hat.std::vector<bool> v;
wird kompiliert.&v[0]
wird nicht (Adresse eines temporären nehmen).vector<bool>
hat einen schlechten Ruf, aber nicht ganz zu Recht: isocpp.org/blog/2012/11/on-vectorboolAntworten:
Aus Gründen der Speicherplatzoptimierung wird der C ++ - Standard (bereits in C ++ 98) explizit
vector<bool>
als spezieller Standardcontainer aufgerufen, in dem jeder Bool nur ein Bit Speicherplatz anstelle eines Bytes wie ein normaler Bool verwendet (Implementierung einer Art von "dynamisches Bitset"). Im Gegenzug für diese Optimierung bietet es nicht alle Funktionen und Schnittstellen eines normalen Standardcontainers.In diesem Fall können Dinge wie a
operator[]
nicht zurückgeben,bool&
sondern ein Proxy-Objekt zurückgeben, mit dem das betreffende Bit bearbeitet werden kann, da Sie die Adresse eines Bits nicht innerhalb eines Bytes übernehmen können . Da es sich bei diesem Proxy-Objekt nicht um ein handeltbool&
, können Sie seine Adresse nicht einembool*
ähnlichen Objekt zuweisen, wie dies bei einem solchen Operatoraufruf für einen "normalen" Container der Fall wäre. Dies bedeutet wiederum, dass derbool *pb =&v[0];
Code nicht gültig ist.Auf der anderen Seite
deque
wird keine solche Spezialisierung aufgerufen, sodass jeder Bool ein Byte benötigt und Sie die Adresse des Wertes verwenden können, von dem zurückgegeben wirdoperator[]
.Beachten Sie schließlich, dass die Implementierung der MS-Standardbibliothek (wohl) suboptimal ist, da sie eine kleine Blockgröße für Deques verwendet, was bedeutet, dass die Verwendung von Deque als Ersatz nicht immer die richtige Antwort ist.
quelle
std::array
ist lediglich ein Vorlagen-Wrapper um ein rohes ArrayT[n]
mit einigen Hilfsfunktionen wiesize()
Kopier- / Verschiebungssemantik und Iteratoren, die hinzugefügt wurden, um es STL-kompatibel zu machen - und (zum Glück) verstößt es nicht gegen seine eigenen Prinzipien (beachten Sie meine Skepsis gegenüber diesen :) 'spezialisieren' für 'bool
'.vector<bool>
enthält boolesche Werte in komprimierter Form, wobei nur ein Bit für den Wert verwendet wird (und nicht 8, wie es bool [] -Arrays tun). Es ist nicht möglich, einen Verweis auf ein Bit in c ++ zurückzugeben, daher gibt es einen speziellen Hilfstyp, "Bitreferenz", der Ihnen eine Schnittstelle zu einem Bit im Speicher bietet und die Verwendung von Standardoperatoren und Casts ermöglicht.quelle
deque<bool>
ist nicht spezialisiert, es ist also buchstäblich nur eine Deque, die Bools hält.vector<bool>
verfügt über eine bestimmte Vorlagenimplementierung. Ich denke, andere STL-Container, wie z. B.deque<bool>
nicht, enthalten Bool-s wie alle anderen Typen.Das Problem besteht darin, dass anstelle einer echten Referenz
vector<bool>
ein Proxy-Referenzobjekt zurückgegeben wird , sodass der Codebool * p = &v[0];
im C ++ 98-Stil nicht kompiliert wird. Modernes C ++ 11 mitauto p = &v[0];
kann jedoch kompiliert werden, wennoperator&
auch ein Proxy-Zeigerobjekt zurückgegeben wird . Howard Hinnant hat einen Blog-Beitrag geschrieben, in dem die algorithmischen Verbesserungen bei der Verwendung solcher Proxy-Referenzen und Zeiger beschrieben werden.Scott Meyers hat einen langen Artikel 30 in Effective C ++ über Proxy-Klassen. Sie können einen langen Weg zurücklegen, um die eingebauten Typen fast nachzuahmen: Für jeden gegebenen Typ
T
kann ein Paar von Proxys (z. B.reference_proxy<T>
unditerator_proxy<T>
) in dem Sinne miteinander konsistent gemacht werden, dassreference_proxy<T>::operator&()
unditerator_proxy<T>::operator*()
umgekehrt sind.Irgendwann muss man jedoch die Proxy-Objekte wieder zuordnen, um sich wie
T*
oder zu verhaltenT&
. Bei Iterator-Proxys kann man die Benutzeroberflächeoperator->()
der Vorlage überladen und darauf zugreifenT
, ohne die gesamte Funktionalität neu zu implementieren. Für Referenz-Proxys müssten Sie jedoch überladenoperator.()
, was in aktuellem C ++ nicht zulässig ist (obwohl Sebastian Redl einen solchen Vorschlag auf der BoostCon 2013 vorgelegt hat). Sie können eine ausführliche Problemumgehung wie ein.get()
Mitglied im Referenz-Proxy durchführen oder die gesamteT
Schnittstelle in der Referenz implementieren (hierfür wird gearbeitet)vector<bool>::bit_reference
), aber dies verliert entweder die eingebaute Syntax oder führt benutzerdefinierte Konvertierungen ein, die keine integrierte Semantik für Typkonvertierungen haben (Sie können höchstens eine benutzerdefinierte Konvertierung pro Argument haben).TL; DR : no
vector<bool>
ist kein Container, da der Standard eine echte Referenz erfordert, aber es kann bewirkt werden, dass es sich fast wie ein Container verhält, zumindest viel näher mit C ++ 11 (auto) als mit C ++ 98.quelle
Viele halten die
vector<bool>
Spezialisierung für einen Fehler.In einem Artikel "Verwerfen von Restbibliotheksteilen in C ++ 17"
wird vorgeschlagen, die Teilspezialisierung von Vektoren zu überdenken .
quelle
Schauen Sie sich an, wie es implementiert wird. Die STL baut weitgehend auf Vorlagen auf, und daher enthalten die Header den Code, den sie enthalten.
Schauen Sie sich hier zum Beispiel die stdc ++ - Implementierung an .
auch interessant, obwohl kein stl- konformer bitvektor der llvm :: bitVector von hier ist .
Die Essenz von
llvm::BitVector
ist eine verschachtelte Klasse namensreference
und eine geeignete Überladung von Operatoren, um dasBitVector
Verhaltenvector
mit einigen Einschränkungen ähnlich zu machen . Der folgende Code ist eine vereinfachte Schnittstelle, die zeigt, wie BitVector eine aufgerufene Klasse verbirgtreference
, damit sich die reale Implementierung fast wie ein echtes Array von Bool verhält, ohne 1 Byte für jeden Wert zu verwenden.Dieser Code hier hat die schönen Eigenschaften:
Dieser Code hat tatsächlich einen Fehler. Versuchen Sie Folgendes auszuführen:
wird nicht funktionieren, weil
assert( (&b[5] - &b[3]) == (5 - 3) );
(innerhalbllvm::BitVector
) fehlschlagen wirdDies ist die sehr einfache llvm-Version.
std::vector<bool>
hat auch funktionierende Iteratoren drin. Somitfor(auto i = b.begin(), e = b.end(); i != e; ++i)
funktioniert der Anruf . und auchstd::vector<bool>::const_iterator
.Es gibt jedoch immer noch Einschränkungen
std::vector<bool>
, die dazu führen, dass es sich in einigen Fällen anders verhält .quelle
Dies kommt von http://www.cplusplus.com/reference/vector/vector-bool/
quelle