Ich frage mich warum cbegin
und cend
wurden in C ++ 11 eingeführt?
Was sind Fälle, in denen der Aufruf dieser Methoden einen Unterschied zu konstanten Überladungen von begin
und macht end
?
Ich frage mich warum cbegin
und cend
wurden in C ++ 11 eingeführt?
Was sind Fälle, in denen der Aufruf dieser Methoden einen Unterschied zu konstanten Überladungen von begin
und macht end
?
Es ist ganz einfach. Angenommen, ich habe einen Vektor:
std::vector<int> vec;
Ich fülle es mit einigen Daten. Dann möchte ich ein paar Iteratoren dazu bringen. Vielleicht geben Sie sie weiter. Vielleicht zu std::for_each
:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
In C ++ 03 SomeFunctor
war es frei, den erhaltenen Parameter ändern zu können . Sicher, SomeFunctor
könnte seinen Parameter nach Wert oder nach nehmen const&
, aber es gibt keine Möglichkeit, dies sicherzustellen . Nicht ohne so etwas Dummes zu tun:
const std::vector<int> &vec_ref = vec;
std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());
Nun stellen wir vor cbegin/cend
:
std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());
Jetzt haben wir syntaktische Zusicherungen, SomeFunctor
die die Elemente des Vektors nicht ändern können (natürlich ohne const-cast). Wir bekommen explizit const_iterator
s und werden daher SomeFunctor::operator()
mit aufgerufen const int &
. Wenn die Parameter als verwendet werden int &
, gibt C ++ einen Compilerfehler aus.
C ++ 17 bietet eine elegantere Lösung für dieses Problem : std::as_const
. Nun, zumindest ist es elegant, wenn man Range-basiert verwendet for
:
for(auto &item : std::as_const(vec))
Dies gibt einfach ein const&
an das bereitgestellte Objekt zurück.
std::cbegin/cend
freien Funktionen, wie siestd::begin/std::end
existieren. Es war ein Versehen des Komitees. Wenn diese Funktionen vorhanden wären, würden sie im Allgemeinen so verwendet.std::cbegin/cend
wird in C ++ 14 hinzugefügt. Siehe en.cppreference.com/w/cpp/iterator/beginfor(auto &item : std::as_const(vec))
entsprichtfor(const auto &item : vec)
?const
auf die Referenz setzen. Nicol betrachtet den Container als const undauto
leitet daher eineconst
Referenz ab. IMOauto const& item
ist einfacher und klarer. Es ist unklar, warumstd::as_const()
hier gut ist; Ich kann sehen, dass es nützlich wäre, wenn etwas nichtconst
an generischen Code übergeben wird, bei dem wir den verwendeten Typ nicht steuern können, aber mit Rangefor
können wir das. Es scheint mir also nur ein zusätzliches Rauschen zu sein.Betrachten Sie über das hinaus, was Nicol Bolas in seiner Antwort gesagt hat , das neue
auto
Schlüsselwort:Mit
auto
kann nicht sichergestellt werden, dassbegin()
ein konstanter Operator für eine nicht konstante Containerreferenz zurückgegeben wird. Jetzt machst du also:quelle
const_iterator
ist dies nur eine weitere Kennung. Keine der Versionen verwendet eine Suche nach den üblichen Mitgliedertypedefsdecltype(container)::iterator
oderdecltype(container)::const_iterator
.const_iterator
mit erhaltenauto
: Schreiben Sie eine Hilfsfunktionsvorlage, die aufgerufen wirdmake_const
, um das Objektargument zu qualifizieren.Nehmen Sie dies als praktischen Anwendungsfall
Die Zuweisung schlägt fehl, da
it
es sich um einen nicht konstanten Iterator handelt. Wenn Sie anfänglich cbegin verwendet hätten, hätte der Iterator den richtigen Typ gehabt.quelle
Von http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf :
Sie gaben dieses Beispiel
Beachten Sie, dass im Arbeitspapier auch Adaptervorlagen erwähnt werden, die jetzt als
std::begin()
und finalisiert wurdenstd::end()
und auch mit nativen Arrays funktionieren. Die entsprechendenstd::cbegin()
undstd::cend()
fehlen ab diesem Zeitpunkt merkwürdigerweise, können aber auch hinzugefügt werden.quelle
Ich bin gerade auf diese Frage gestoßen ... Ich weiß, dass sie bereits beantwortet wurde und nur ein Seitenknoten ist ...
auto const it = container.begin()
ist dann ein anderer Typauto it = container.cbegin()
der Unterschied für
int[5]
(mit Zeiger, von dem ich weiß, dass er nicht die Methode begin hat, aber den Unterschied gut zeigt ... aber in c ++ 14 fürstd::cbegin()
und funktionieren würdestd::cend()
, was man im Wesentlichen verwenden sollte, wenn er hier ist) ...quelle
iterator
undconst_iterator
Vererbungsbeziehung haben und eine implizite Konvertierung erfolgt, wenn sie mit dem anderen Typ verglichen oder diesem zugewiesen wird.Die Verwendung von
cbegin()
undcend()
erhöht in diesem Fall die Leistung.quelle
const
Hauptvorteil die Leistung ist (was nicht der Fall ist : semantisch korrekter und sicherer Code). Aber während Sie einen Punkt haben, macht (A)auto
das zu einem Nicht-Problem; (B) Wenn Sie über die Leistung sprechen, haben Sie eine wichtige Sache übersehen, die Sie hier hätten tun sollen: Zwischenspeichern Sie denend
Iterator, indem Sie eine Kopie davon im Init-Zustand derfor
Schleife deklarieren , und vergleichen Sie diese, anstatt eine neue Kopie von zu erhalten Wert für jede Iteration. Das wird Ihren Standpunkt verbessern. : Pconst
kann definitiv dazu beitragen, eine bessere Leistung zu erzielen, nicht aufgrund von Magie imconst
Schlüsselwort selbst, sondern weil der Compiler einige Optimierungen aktivieren kann, wenn er weiß, dass die Daten nicht geändert werden, was sonst nicht möglich wäre. Schauen Sie sich dieses Stück aus einem Vortrag von Jason Turner an, um ein Live-Beispiel dafür zu erhalten.const
dies (fast indirekt) zu Leistungsvorteilen führen kann. Nur für den Fall, dass jemand, der dies liest, denkt: "Ich werde mich nicht darum kümmern, etwas hinzuzufügen,const
wenn der generierte Code in keiner Weise beeinflusst wird", was nicht stimmt.Sein einfacher cbegin gibt einen konstanten Iterator zurück, wobei begin nur einen Iterator zurückgibt
Zum besseren Verständnis nehmen wir hier zwei Szenarien
Szenario 1 :
Dies wird ausgeführt, da hier der Iterator i nicht konstant ist und um 5 erhöht werden kann
Verwenden wir nun cbegin und cend, um sie als konstantes Iteratorszenario zu bezeichnen - 2:
Dies wird nicht funktionieren, da Sie den Wert nicht mit cbegin und cend aktualisieren können, wodurch der konstante Iterator zurückgegeben wird
quelle