Перейти к содержимому
Теория · Ссылки и указатели · урок 1 из 8

Ссылки, lvalue и rvalue

Ссылка (reference) бывает не только параметром (parameter) функции. Её можно объявить и как обычную переменную — тогда она становится вторым именем другой переменной:

C++
#include <iostream>

int main() {
    int score = 10;
    int& ref = score;
    ref = ref + 5;
    std::cout << score << '\n';  // 15
}

ref — не новая переменная и не копия. ref и score обозначают одно место в памяти, поэтому изменение через одно имя видно через другое. Ссылка, инициализированная другой ссылкой, привязывается к той же переменной: после int& alias = ref; имя alias тоже обозначает score.

Одна переменная навсегда

Переменную для ссылки выбирают один раз — при объявлении (declaration). Поэтому ссылка без инициализатора не компилируется: int& ref; — ошибка. Перепривязать ссылку к другой переменной потом тоже нельзя. Присваивание через ссылку меняет значение переменной, к которой она привязана:

C++
#include <iostream>

int main() {
    int first = 10;
    int second = 20;
    int& ref = first;
    ref = second;
    std::cout << first << ' ' << second << '\n';  // 20 20
}

Строка ref = second; записывает в first значение second, то есть 20. После неё ref по-прежнему обозначает first: если потом изменить second, ни first, ни ref не изменятся.

К чему привязывается ссылка

Выражение, которое обозначает переменную, называют lvalue: например, score или ref. Литерал 5 или результат score + 1 — это rvalue: значение без имени, которое не хранится ни в одной переменной. Ссылка int& привязывается только к lvalue.

Константная ссылка const int& принимает и rvalue. Для такого значения компилятор (compiler) создаёт временный объект (temporary object) — безымянную переменную, в которой оно хранится, — и привязывает ссылку к нему. Такой объект живёт, пока существует ссылка:

C++
#include <iostream>

int main() {
    int score = 10;
    const int& next = score + 1;
    score = 50;
    std::cout << next << '\n';  // 11
}

next обозначает временный объект со значением 11, а не score, поэтому изменение score его не задевает. По той же причине параметр const int& принимает литералы и выражения.

Частая ошибка

Обычную ссылку привязывают к результату выражения:

C++
int main() {
    int a = 2;
    int b = 3;
    int& sum = a + b;  // ✗
    return sum;
}
TEXT
error: non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'

a + b — rvalue: сумма не хранится ни в одной переменной, поэтому int& к ней не привязывается. Если менять sum не нужно, объявите её как const int&. Но чаще здесь нужна обычная переменная: int sum = a + b;.