range-for (for (x : colecție)) în C++

Parcurge pe rând toate elementele unei colecții (vector, tablou, string, map) fără index și fără iteratori scriși de mână.

Sintaxă
for (declarație : colecție) { ... }
for (const auto& x : v) { ... }
for (auto& x : v) { ... }           // modificare
for (init; declarație : colecție)    // C++20

Ce face range-for (for (x : colecție))

Bucla range-for (bazată pe interval) ia pe rând fiecare element al colecției și îl pune în variabila din stânga lui :. Merge cu orice are begin() și end(): std::vector, std::string, std::map, tablouri clasice, liste de inițializare {1, 2, 3}, intervale din std::views.

Cum declari variabila contează: auto x face o copie (bine pentru numere), const auto& x doar citește fără copie (bine pentru texte și obiecte mari), iar auto& x îți permite să modifici elementele.

Din C++20 poți pune o inițializare înainte, ca la if: for (int i = 0; const auto& x : v), util când îți trebuie și un contor.

Exemple

Exemplul 1: Citire, modificare și text

#include <print>
#include <string>
#include <vector>

int main() {
    std::vector<int> note = {7, 9, 6, 10};
    int suma = 0;
    for (int n : note) {
        suma += n;
    }
    std::println("Suma: {}", suma);

    for (int& n : note) {
        n += 1;  // modificăm chiar elementele
    }
    std::println("Note mărite: {}", note);

    for (char c : std::string("ABC")) {
        std::print("{}-", c);
    }
    std::println("");
}

Rezultat

Suma: 32
Note mărite: [8, 10, 7, 11]
A-B-C-

Exemplul 2: Parcurgerea unui map

Elementele unui std::map sunt perechi (cheie, valoare), ordonate după cheie; legăturile structurate le desfac în două nume.

#include <map>
#include <print>
#include <string>

int main() {
    std::map<std::string, double> cos = {{"cafea", 32.5}, {"zahăr", 6.0}, {"lapte", 7.2}};
    double total = 0;
    for (const auto& [produs, pret] : cos) {
        std::println("{:<8}{:>7.2f} lei", produs, pret);
        total += pret;
    }
    std::println("Total: {:.2f} lei", total);
}

Rezultat

cafea     32.50 lei
lapte      7.20 lei
zahăr      6.00 lei
Total: 45.70 lei

Exemplul 3: Cu inițializare (C++20)

#include <print>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> orase = {"Iași", "Timișoara", "Constanța"};
    for (int loc = 1; const auto& oras : orase) {
        std::println("{}. {}", loc++, oras);
    }
}

Rezultat

1. Iași
2. Timișoara
3. Constanța

Greșeli frecvente

  • Scrii for (auto x : v) și modifici x. Modifici o copie; folosește auto& x.
  • Adaugi sau ștergi elemente din vector în timpul buclei. Bucla folosește iteratori care pot deveni invalizi: comportament nedefinit.
  • Parcurgi rezultatul unei funcții care returnează o referință în interiorul unui obiect temporar (for (auto x : creeaza().lista())). Temporarul este distrus înainte de buclă (până la C++23); salvează întâi obiectul într-o variabilă.

Comenzi înrudite

  • for: Bucla cu contor: repetă un bloc de cod cât timp condiția este adevărată, cu inițializare și pas scrise pe același rând.
  • auto: Lasă compilatorul să deducă tipul variabilei din valoarea cu care este inițializată.
  • structured bindings (auto [a, b]): Desface o pereche, un tuplu, o structură sau un tablou în variabile separate, cu nume, într-o singură declarație.
  • referințe (&, &&): O referință este un alt nume pentru o variabilă existentă; tot ce faci cu referința se face de fapt cu variabila originală.
  • std::vector: Tabloul dinamic din C++: ține elementele unul după altul în memorie și își mărește singur dimensiunea.