Ce face referințe (&, &&)
int& r = x; face din r un alt nume pentru x. Nu se copiază nimic: r = 10; schimbă chiar x. O referință trebuie legată de o variabilă la declarare și nu mai poate fi mutată pe alta. Nu există „referință nulă”.
Cea mai importantă folosire este la parametri. void f(int& x) poate modifica variabila celui care apelează. void f(const std::string& s) primește textul fără să-l copieze, dar nu îl poate modifica: este forma standard pentru obiecte mari pe care doar le citești.
Din C++11 există și referințele rvalue (T&&), care se leagă de obiecte temporare sau marcate cu std::move. Prin ele se implementează mutarea: în loc să copiezi un vector mare, îi „furi” conținutul, pentru că originalul oricum nu mai este folosit.
Exemple
Exemplul 1: Referința ca alt nume
#include <print>
int main() {
int puncte = 50;
int& scor = puncte; // scor este alt nume pentru puncte
scor += 25;
std::println("puncte = {}, scor = {}", puncte, scor);
std::println("Aceeași variabilă: {}", &scor == &puncte);
}
Rezultat
puncte = 75, scor = 75
Aceeași variabilă: true
Exemplul 2: Parametri prin referință
schimba primește referințe, deci modifică variabilele din main. numara_litere primește const&: nu copiază textul și nu îl poate modifica. Prin valoare, schimba nu ar avea niciun efect în afară.
#include <print>
#include <string>
void schimba(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int numara_litere(const std::string& text, char litera) {
int n = 0;
for (char c : text) {
if (c == litera) ++n;
}
return n;
}
int main() {
int x = 1, y = 2;
schimba(x, y);
std::println("x = {}, y = {}", x, y);
std::println("Litere 'a' în \"banana\": {}", numara_litere("banana", 'a'));
}
Rezultat
x = 2, y = 1
Litere 'a' în "banana": 3
Exemplul 3: Referințe rvalue și std::move
Prima funcție este aleasă pentru variabile obișnuite, a doua pentru temporare și pentru obiecte date cu std::move. După mutare, text este într-o stare validă, dar nespecificată (aici, gol); nu te baza pe conținutul lui.
#include <print>
#include <string>
#include <utility>
#include <vector>
std::vector<std::string> arhiva;
void salveaza(const std::string& s) {
std::println("copiez: {}", s);
arhiva.push_back(s);
}
void salveaza(std::string&& s) {
std::println("mut: {}", s);
arhiva.push_back(std::move(s));
}
int main() {
std::string text = "raport lunar";
salveaza(text);
salveaza(std::string("factură"));
salveaza(std::move(text));
std::println("Elemente în arhivă: {}, text gol: {}", arhiva.size(), text.empty());
}
Rezultat
copiez: raport lunar
mut: factură
mut: raport lunar
Elemente în arhivă: 3, text gol: true
Greșeli frecvente
- Returnezi o referință la o variabilă locală (
const std::string& f() { std::string s = "x"; return s; }). Variabila dispare la ieșirea din funcție; returnează prin valoare. - Ții o referință la un element dintr-un
std::vectorși apoi facipush_back. Vectorul își poate muta elementele în altă zonă de memorie, iar referința devine invalidă. - Folosești o variabilă după
std::moveca și cum ar avea încă valoarea veche. După mutare, poți doar să-i dai o valoare nouă sau să o distrugi.
Comenzi înrudite
pointeri (*, &): Un pointer este o variabilă care ține adresa altei variabile; prin el poți citi și modifica valoarea de la acea adresă.const: Marchează o valoare care nu mai poate fi modificată după inițializare; compilatorul oprește orice încercare de schimbare.range-for (for (x : colecție)): 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ă.auto: Lasă compilatorul să deducă tipul variabilei din valoarea cu care este inițializată.std::move: Mută elementele unui interval la o destinație, fără să le copieze (versiunea din <algorithm>).