Was ist der Vorteil der Verwendung von Weiterleitungsreferenzen in bereichsbasierten for-Schleifen?

Lesezeit: 6 Minuten

Was ist der Vorteil der Verwendung von Weiterleitungsreferenzen in bereichsbasierten
Ali

const auto& würde ausreichen, wenn ich Nur-Lese-Operationen durchführen möchte. Allerdings bin ich 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 obskuren Eckfällen ein Leistungsvorteil durch die Verwendung von Weiterleitungsreferenzen im Vergleich zu auto& oder const auto&?

(shared_ptr ist ein Verdächtiger für obskure Eckfälle)


Aktualisieren
Zwei Beispiele, die ich in meinen Favoriten gefunden habe:

Irgendein Nachteil der Verwendung von const-Referenzen beim Iterieren über Basistypen?
Kann ich mit einer bereichsbasierten for-Schleife problemlos über die Werte einer Karte iterieren?

Konzentrieren Sie sich bitte auf die Frage: Warum sollte ich auto&& in bereichsbasierten for-Schleifen verwenden wollen?

  • Tust du Ja wirklich “oft” sehen?

    – Leichtigkeitsrennen im Orbit

    29. Oktober 2012 um 22:44 Uhr

  • Ich bin mir nicht sicher, ob Ihre Frage genügend Kontext enthält, um einzuschätzen, wie “verrückt” es ist, wo Sie es sehen.

    – Leichtigkeitsrennen im Orbit

    29. Oktober 2012 um 22:49 Uhr

  • @LightnessRacesinOrbit Lange Rede kurzer Sinn: Warum sollte ich verwenden wollen auto&& in bereichsbasierten for-Schleifen?

    – Ali

    29. Oktober 2012 um 22:52 Uhr

1646878209 757 Was ist der Vorteil der Verwendung von Weiterleitungsreferenzen in bereichsbasierten
Howard Hinnant

Der einzige Vorteil, den ich sehe, ist, wenn der Sequenz-Iterator eine Proxy-Referenz zurückgibt und Sie diese Referenz auf nicht konstante Weise bearbeiten müssen. Betrachten Sie zum Beispiel:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto& e : v)
        e = true;
}

Dies wird nicht kompiliert, weil rvalue vector<bool>::reference von der zurückgekehrt iterator wird nicht an eine nicht konstante lvalue-Referenz gebunden. Aber das wird funktionieren:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto&& e : v)
        e = true;
}

Abgesehen davon würde ich nicht auf diese Weise codieren, es sei denn, Sie wüssten, dass Sie einen solchen Anwendungsfall erfüllen müssen. Dh ich würde das nicht unentgeltlich machen, weil es tut die Leute dazu bringen, sich zu fragen, was du vorhast. Und wenn ich es getan habe, würde es nicht schaden, einen Kommentar dazu hinzuzufügen, warum:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    // using auto&& so that I can handle the rvalue reference
    //   returned for the vector<bool> case
    for (auto&& e : v)
        e = true;
}

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, dann auto würde auch funktionieren auto&&. Aber wenn die Schleife manchmal Nicht-Proxy-Referenzen und manchmal Proxy-Referenzen handhabte, dann denke ich auto&& wäre die Lösung der Wahl.

  • Auf der anderen Seite gibt es keine explizite Nachteil, Gibt es? (Abgesehen von der potenziellen Verwirrung der Menschen, was meiner Meinung nach persönlich nicht besonders erwähnenswert ist.)

    – Ildjarn

    29. Oktober 2012 um 22:55 Uhr


  • Ein anderer Begriff für das Schreiben von Code, der Menschen unnötig verwirrt, ist: Verwirrten Code schreiben. Es ist am besten, Ihren Code so einfach wie möglich zu gestalten, aber nicht einfacher. Dies wird dazu beitragen, den Fehlerzähler niedrig zu halten. Davon abgesehen, wenn && bekannter wird, werden die Leute vielleicht in 5 Jahren ein Auto&&-Idiom erwarten (vorausgesetzt, es schadet tatsächlich nicht). Ich weiß nicht, ob das passieren wird oder nicht. Aber einfach liegt im Auge des Betrachters, und wenn Sie für mehr als nur sich selbst schreiben, berücksichtigen Sie Ihre Leser.

    – Howard Hinnant

    29. Oktober 2012 um 23:02 Uhr

  • ich bevorzuge const auto& wenn ich möchte, dass der Compiler mir hilft zu überprüfen, ob ich nicht versehentlich die Elemente in der Sequenz ändere.

    – Howard Hinnant

    29. Oktober 2012 um 23:04 Uhr

  • verwende ich persönlich gerne auto&& in generischem Code, wo ich die Elemente der Sequenz ändern muss. Wenn nicht, bleibe ich einfach dabei auto const&.

    – Xeo

    29. Oktober 2012 um 23:08 Uhr

  • @Xeo: +1 Aufgrund von Enthusiasten wie Ihnen, die ständig experimentieren und nach besseren Möglichkeiten drängen, Dinge zu tun, entwickelt sich C++ ständig weiter. Danke. 🙂

    – Howard Hinnant

    29. Oktober 2012 um 23:13 Uhr

Verwenden auto&& oder universelle Referenzen mit einem bereichsbasierten for-loop hat den Vorteil, dass Sie erfassen, was Sie erhalten. Für die meisten Arten von Iteratoren erhalten Sie wahrscheinlich entweder a T& oder ein T const& für irgendeinen Typ T. Der interessante Fall ist, wo die Dereferenzierung eines Iterators einen temporären Wert ergibt: C++ 2011 hat gelockerte Anforderungen und Iteratoren müssen nicht unbedingt einen lvalue liefern. Die Verwendung von universellen Referenzen entspricht der Argumentweiterleitung in std::for_each():

template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
    for (; it != end; ++it) {
        f(*it); // <---------------------- here
    }
    return f;
}

Das Funktionsobjekt f behandeln kann T&, T const&und T anders. Warum sollte der Körper eines Bereichs basieren for-Schleife anders sein? Um tatsächlich davon zu profitieren, den Typ anhand universeller Referenzen abgeleitet zu haben, müssten Sie diese natürlich entsprechend weitergeben:

for (auto&& x: range) {
    f(std::forward<decltype(x)>(x));
}

Natürlich mit std::forward() bedeutet, dass Sie alle zurückgegebenen Werte akzeptieren, von denen verschoben werden soll. Ob solche Objekte in Nicht-Template-Code 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. Bei Template-Code bleibt es außen vor, Entscheidungen darüber zu treffen, was mit den Objekten passieren soll.

benutze ich praktisch immer auto&&. Warum von einem Grenzfall gebissen werden, wenn Sie nicht müssen? Es ist auch kürzer zum Tippen und ich finde es einfach … transparenter. Wenn Sie verwenden auto&& xdann weißt du das x ist genau *itjedes Mal.

  • Mein Problem ist, dass du aufgibst const-ness mit auto&& wenn const auto& genügt. Die Frage fragt nach den Eckfällen, in denen ich gebissen werden kann. Welche Eckfälle wurden von Dietmar oder Howard noch nicht erwähnt?

    – Ali

    30. Oktober 2012 um 20:19 Uhr


  • Hier ist eine Möglichkeit, gebissen zu werden, wenn Sie tun verwenden auto&&. Wenn der Typ, den Sie erfassen, zum Beispiel in den Schleifenkörper verschoben werden soll und zu einem späteren Zeitpunkt geändert wird, wird er in a aufgelöst const& eingeben, wird Ihr Code stillschweigend weiter funktionieren, aber Ihre Züge werden Kopien sein. Dieser Code wird sehr trügerisch sein. Wenn Sie den Typ jedoch explizit als R-Wert-Referenz angeben, erhält jeder, der den Containertyp geändert hat, einen Kompilierungsfehler, weil Sie wirklich wollten, dass diese Objekte verschoben und nicht kopiert werden …

    – Cyberbisson

    10. April 2019 um 20:03 Uhr

  • @cyberbisson Ich bin gerade darauf gestoßen: Wie kann ich eine Rvalue-Referenz erzwingen, ohne den Typ explizit anzugeben? Etwas wie for (std::decay_t<decltype(*v.begin())>&& e: v)? Ich denke, es gibt einen besseren Weg …

    – Jerry Ma

    10. April 2019 um 22:25 Uhr


  • @JerryMa Es hängt davon ab, was Sie tun über den Typ Bescheid wissen. Wie oben erwähnt, auto&& gibt eine “universelle Referenz”, also alles andere als das wird Ihnen einen spezifischeren Typ geben. Wenn v wird als a angenommen vectordu könntest es tun decltype(v)::value_type&&was Sie vermutlich wollten, indem Sie das Ergebnis von nehmen operator* auf einem Iteratortyp. Könntest du auch machen decltype(begin(v))::value_type&& um die Typen des Iterators anstelle des Containers zu überprüfen. Wenn wir jedoch so wenig Einblick in den Typ haben, könnten wir es für etwas klarer halten, einfach mitzumachen auto&&

    – Cyberbisson

    11. April 2019 um 17:06 Uhr

985620cookie-checkWas ist der Vorteil der Verwendung von Weiterleitungsreferenzen in bereichsbasierten for-Schleifen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy