const auto&
würde ausreichen, wenn ich schreibgeschützte Operationen ausführen möchte. Ich bin jedoch darauf gestoßen
for (auto&& e : v) // v is non-const
ein paar Mal in letzter Zeit. Das wundert mich:
Ist es möglich, dass in einigen dunklen Eckfällen die Verwendung von Weiterleitungsreferenzen im Vergleich zu auto&
oder einen gewissen Leistungsvorteil bietet const auto&
?
( shared_ptr
ist ein Verdächtiger für obskure Eckfälle)
Update Zwei Beispiele, die ich in meinen Favoriten gefunden habe:
Gibt es einen Nachteil bei der Verwendung von const-Referenzen beim Durchlaufen von Basistypen?
Kann ich die Werte einer Karte mithilfe einer bereichsbasierten for-Schleife problemlos durchlaufen?
Bitte konzentrieren Sie sich auf die Frage: Warum sollte ich auto && in bereichsbasierten for-Schleifen verwenden?
auto&&
for-Schleifen verwenden?Antworten:
Der einzige Vorteil, den ich sehen kann, ist, wenn der Sequenziterator eine Proxy-Referenz zurückgibt und Sie diese Referenz auf eine nicht konstante Weise bearbeiten müssen. Betrachten Sie zum Beispiel:
Dies lässt sich nicht kompilieren , weil rvalue
vector<bool>::reference
aus der zurückiterator
wird lvalue Referenz nicht binden an eine nicht-const. Aber das wird funktionieren:Abgesehen davon würde ich nicht so codieren, wenn Sie nicht wüssten, dass Sie einen solchen Anwendungsfall erfüllen müssen. Dh ich würde dies grundlos nicht tun , weil es tut Ursache Menschen zu fragen , was Sie vorhaben. Und wenn ich es tun würde, würde es nicht schaden, einen Kommentar dazu aufzunehmen, warum:
Bearbeiten
Dieser letzte Fall von mir sollte wirklich eine Vorlage sein, um Sinn zu machen. Wenn Sie wissen, dass die Schleife immer eine Proxy-Referenz verarbeitet,
auto
funktioniert dies genauso gut wieauto&&
. Aber wenn die Schleife manchmal Nicht-Proxy-Referenzen und manchmal Proxy-Referenzen handhabte, dann würde ich denkeauto&&
, die Lösung der Wahl werden.quelle
const auto&
wenn der Compiler mir helfen soll, zu überprüfen, ob ich die Elemente in der Sequenz nicht versehentlich ändere.auto&&
generischen Code, bei dem ich die Elemente der Sequenz ändern muss. Wenn ich es nicht tue, bleibe ich einfach beiauto const&
.Die Verwendung von
auto&&
oder universellen Referenzen mit einerfor
bereichsbasierten Schleife hat den Vorteil, dass Sie erfassen, was Sie erhalten. Für die meisten Arten von Iteratoren erhalten Sie wahrscheinlich entweder einenT&
oder einenT const&
für einen TypT
. Der interessante Fall ist, wenn die Dereferenzierung eines Iterators eine temporäre ergibt: C ++ 2011 hat entspannte Anforderungen und Iteratoren müssen nicht unbedingt einen l-Wert liefern. Die Verwendung universeller Referenzen entspricht der Argumentweiterleitung instd::for_each()
:Das Funktionsobjekt
f
kann behandelnT&
,T const&
undT
anders. Warum sollte der Körper einerfor
bereichsbasierten Schleife anders sein? Um den Typ tatsächlich unter Verwendung universeller Referenzen ableiten zu können, müssen Sie sie natürlich entsprechend weitergeben:Verwenden
std::forward()
bedeutet natürlich, dass Sie alle zurückgegebenen Werte akzeptieren, aus denen verschoben werden soll. Ob solche Objekte in Nicht-Vorlagencode viel Sinn machen, weiß ich (noch?) Nicht. Ich kann mir vorstellen, dass die Verwendung universeller Referenzen dem Compiler mehr Informationen bieten kann, um das Richtige zu tun. Im Vorlagencode wird keine Entscheidung darüber getroffen, was mit den Objekten geschehen soll.quelle
Ich benutze praktisch immer
auto&&
. Warum von einem Randfall gebissen werden, wenn Sie nicht müssen? Es ist auch kürzer zu tippen und ich finde es einfach ... transparenter. Wenn Sie verwendenauto&& x
, wissen Sie jedes Malx
genau*it
, dass .quelle
const
-ness mit ,auto&&
wennconst auto&
genügt. Die Frage fragt nach den Eckfällen, in denen ich gebissen werden kann. Was sind die Eckfälle, die Dietmar oder Howard noch nicht erwähnt haben?auto&&
. Wenn der Typ, den Sie erfassen, beispielsweise im Hauptteil der Schleife verschoben werden soll und zu einem späteren Zeitpunkt geändert wird, damit er in einenconst&
Typ aufgelöst wird, funktioniert Ihr Code stillschweigend weiter, Ihre Verschiebungen werden jedoch kopiert. Dieser Code wird sehr irreführend sein. Wenn Sie den Typ jedoch explizit als R-Wert-Referenz angeben, wird bei jedem, der den Containertyp geändert hat, ein Kompilierungsfehlerfor (std::decay_t<decltype(*v.begin())>&& e: v)
? Ich denke, es gibt einen besseren Weg ...auto&&
wird eine "universelle Referenz" angegeben, sodass Sie durch alles andere einen spezifischeren Typ erhalten. Wennv
angenommen wird, dass es sich um a handeltvector
, können Sie dies tundecltype(v)::value_type&&
. Ich gehe davon aus, dass Sie dies wollten, indem Sie das Ergebnisoperator*
eines Iteratortyps verwenden. Sie können auchdecltype(begin(v))::value_type&&
die Typen des Iterators anstelle des Containers überprüfen. Wenn wir jedoch so wenig Einblick in den Typ haben, könnten wir es als etwas klarer betrachten, einfach mitauto&&
...