Bereichsbasierte Schleife: Element nach Wert oder Verweis auf const abrufen?

Lesezeit: 5 Minuten

Bereichsbasierte Schleife Element nach Wert oder Verweis auf const abrufen
masud

Beim Lesen einiger Beispiele für bereichsbasierte Schleifen schlagen sie zwei Hauptwege vor 1, 2, 3, 4

std::vector<MyClass> vec;

for (auto &x : vec)
{
  // x is a reference to an item of vec
  // We can change vec's items by changing x 
}

oder

for (auto x : vec)
{
  // Value of x is copied from an item of vec
  // We can not change vec's items by changing x
}

Brunnen.

Wenn wir keine Veränderung brauchen vec Elemente, IMO, Beispiele schlagen vor, die zweite Version (nach Wert) zu verwenden. Warum sie nicht etwas vorschlagen, was const Referenzen (Zumindest habe ich keinen direkten Vorschlag gefunden):

for (auto const &x : vec) // <-- see const keyword
{
  // x is a reference to an const item of vec
  // We can not change vec's items by changing x 
}

Ist es nicht besser? Vermeidet es nicht eine redundante Kopie in jeder Iteration, während es sich um eine const?

Bereichsbasierte Schleife Element nach Wert oder Verweis auf const abrufen
Nawaz

Wenn Sie die Artikel nicht so gut ändern möchten vermeiden dann Kopien machen auto const & ist die richtige Wahl:

for (auto const &x : vec)

Wer auch immer Ihnen vorschlägt, zu verwenden auto & ist falsch. Ignoriere sie.

Hier ist eine Zusammenfassung:

  • Wählen auto x wenn Sie mit Kopien arbeiten möchten.
  • Wählen auto &x wenn Sie mit Originalartikeln arbeiten und diese modifizieren können.
  • Wählen auto const &x wenn Sie mit Originalelementen arbeiten möchten und diese nicht ändern.

  • Danke für die tolle Antwort. Ich denke, darauf sollte man auch hinweisen const auto &x entspricht Ihrer dritten Wahl.

    – smg

    16. April 2015 um 15:11 Uhr

  • @mloskot: Es ist gleichwertig. (und was meinst du mit “aber es ist die gleiche Syntax”? Die Syntax ist erkennbar anders.)

    – Nawaz

    12. Mai 2015 um 13:25 Uhr

  • Fehlen: auto&& wenn Sie keine unnötige Kopie erstellen möchten und sich nicht darum kümmern, ob Sie sie ändern oder nicht, und einfach nur arbeiten möchten.

    – Yakk – Adam Nevraumont

    13. Mai 2015 um 13:34 Uhr

  • Gilt die Referenzunterscheidung für Kopien, wenn Sie nur mit grundlegenden Typen wie int/double arbeiten?

    Benutzer755921

    30. Januar 2016 um 22:45 Uhr


  • @racarate: Ich kann das nicht kommentieren Gesamt Geschwindigkeit, und ich denke, das kann niemand, ohne vorher ein Profil zu erstellen. Ehrlich gesagt werde ich meine Wahl nicht auf die Geschwindigkeit stützen, sondern auf die Klarheit des Codes. Wenn ich Unveränderlichkeit will, würde ich verwenden const sicher. Allerdings, ob es das wäre auto const &oder auto const hat wenig unterschied. Ich würde wählen auto const & nur um konsequenter zu sein.

    – Nawaz

    1. Februar 2016 um 6:53 Uhr

1646919610 356 Bereichsbasierte Schleife Element nach Wert oder Verweis auf const abrufen
Herr C64

Wenn Sie eine haben std::vector<int> oder std::vector<double>dann ist es gut zu verwenden auto (mit Wert kopieren) statt const auto&seit dem Kopieren eines int oder ein double ist günstig:

for (auto x : vec)
    ....

Aber wenn Sie eine haben std::vector<MyClass>wo MyClass hat eine nicht-triviale Kopiersemantik (z std::stringeine komplexe benutzerdefinierte Klasse usw.), dann würde ich die Verwendung vorschlagen const auto& um tiefe Kopien zu vermeiden:

for (const auto & x : vec)
    ....

1646919610 70 Bereichsbasierte Schleife Element nach Wert oder Verweis auf const abrufen
Andy Prowl

Wenn wir keine Veränderung brauchen vec Elemente, Beispiele schlagen vor, die erste Version zu verwenden.

Dann geben sie einen falschen Vorschlag.

Warum sie nicht etwas vorschlagen, das Referenzen enthält

Weil sie einen falschen Vorschlag machen 🙂 Was Sie erwähnen, ist richtig. Wenn Sie nur wollen beobachten B. ein Objekt, ist es nicht erforderlich, eine Kopie zu erstellen, und es besteht keine Notwendigkeit, ein Nicht-const Verweis darauf.

BEARBEITEN:

Ich sehe, dass die Referenzen, die Sie verlinken, alle Beispiele für die Iteration über eine Reihe von bieten int Werte oder ein anderer grundlegender Datentyp. In diesem Fall, seit dem Kopieren einer int ist nicht teuer, das Erstellen einer Kopie ist im Grunde gleichbedeutend (wenn nicht effizienter als) mit einer Beobachtung const &.

Bei benutzerdefinierten Typen ist dies jedoch im Allgemeinen nicht der Fall. Das Kopieren von UDTs kann teuer sein, und wenn Sie keinen Grund haben, eine Kopie zu erstellen (z. B. das abgerufene Objekt zu ändern, ohne das ursprüngliche zu ändern), verwenden Sie vorzugsweise a const &.

Ich werde hier widersprechen und sagen, dass es keine Notwendigkeit gibt auto const & in einem Bereich basierend auf einer for-Schleife. Sagen Sie mir, ob Sie die folgende Funktion für dumm halten (nicht in ihrem Zweck, aber in der Art, wie sie geschrieben ist):

long long SafePop(std::vector<uint32_t>& v)
{
    auto const& cv = v;
    long long n = -1;
    if (!cv.empty())
    {
        n = cv.back();
        v.pop_back();
    }
    return n;
}

Hier hat der Autor einen const-Verweis auf erstellt v für alle Operationen zu verwenden, die v nicht ändern. Das ist meiner Meinung nach albern, und das gleiche Argument kann für die Verwendung angeführt werden auto const & als Variable in einem Bereich basierend auf for-Schleife statt nur auto &.

1646919611 61 Bereichsbasierte Schleife Element nach Wert oder Verweis auf const abrufen
rnd_nr_gen

würde ich in Betracht ziehen

for (auto&& o : range_expr) { ...}

oder

for (auto&& o : std::as_const(range_expr)) { ...}

es funktioniert immer.

und hüte dich vor möglich Temporärer Bereichsausdruck Tücken.

In C++20 haben Sie so etwas wie

for (T thing = foo(); auto& x : thing.items()) { /* ... */ }

  • Können Sie eine Begründung für die Bevorzugung hinzufügen? auto&& über auto&?

    – Lynden-Schilde

    29. Juli 2021 um 0:41 Uhr

  • @LyndenShields auto&& kann alles binden. auto& wird nicht an rvalue gebunden und funktioniert nicht, wenn range_expression gibt rvalues ​​zurück.

    – rnd_nr_gen

    29. Juli 2021 um 7:32 Uhr

  • gibt es sinnvolle/realistische Beispiele wo range_expression gibt rvalues ​​zurück?

    – Lynden-Schilde

    30. Juli 2021 um 5:07 Uhr


  • gute Frage. Ich habe noch kein Beispiel.

    – rnd_nr_gen

    30. Juli 2021 um 8:47 Uhr

  • Können Sie eine Begründung für die Bevorzugung hinzufügen? auto&& über auto&?

    – Lynden-Schilde

    29. Juli 2021 um 0:41 Uhr

  • @LyndenShields auto&& kann alles binden. auto& wird nicht an rvalue gebunden und funktioniert nicht, wenn range_expression gibt rvalues ​​zurück.

    – rnd_nr_gen

    29. Juli 2021 um 7:32 Uhr

  • gibt es sinnvolle/realistische Beispiele wo range_expression gibt rvalues ​​zurück?

    – Lynden-Schilde

    30. Juli 2021 um 5:07 Uhr


  • gute Frage. Ich habe noch kein Beispiel.

    – rnd_nr_gen

    30. Juli 2021 um 8:47 Uhr

988110cookie-checkBereichsbasierte Schleife: Element nach Wert oder Verweis auf const abrufen?

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

Privacy policy