Параметры: по значению и по ссылке
Представьте, что вы отдаёте коллеге документ на правку. Можно отдать ксерокопию: коллега исчеркает её, а ваш оригинал останется чистым. А можно отдать сам оригинал, и тогда все правки окажутся у вас. Функция в C++ тоже получает аргумент одним из этих двух способов, и по вызову разницу не видно.
Функция inc_copy увеличивает свой параметр на единицу, но переменная, переданная в неё, от этого не меняется:
#include <iostream>
void inc_copy(int x) {
++x;
std::cout << x << '\n'; // 2
}
int main() {
int n = 1;
inc_copy(n);
std::cout << n << '\n'; // 1
}Внутри функции x уже равна 2, а n в main по-прежнему равна 1.
Копия аргумента
Давайте разберём вызов inc_copy(n) по шагам:
- Создаётся новая переменная
x, и в неё копируется значение аргументаn, то есть1. ++xувеличивает копию до2, и функция печатает2.- Функция заканчивается, и
xисчезает вместе со всеми изменениями. mainпечатаетn, аnвсё ещё равна1.
Это передача по значению: функция работает с ксерокопией, а не с самой n. Аналогия хромает в одном: копию нельзя унести с собой, она живёт только до конца функции.
Изменённую копию можно вернуть через return: вызывающий код получит новое значение, а исходная переменная останется прежней.
Параметр-ссылка
Чтобы функция меняла переменную вызывающего кода, параметр объявляют ссылкой: после типа ставят &. Ссылка — другое имя уже существующей переменной, а не её копия. Это как прозвище: «Саша» и «Александр» — один и тот же человек.
#include <iostream>
void inc_ref(int& x) {
++x;
}
int main() {
int n = 1;
inc_ref(n);
std::cout << n << '\n'; // 2
}Внутри inc_ref имя x обозначает саму n, поэтому ++x увеличивает n. Новой переменной при вызове не появляется: у одной переменной на время вызова два имени.
Пройдите оба вызова по шагам и следите за n в рамке main: после inc_copy она прежняя, после inc_ref — уже нет.
1–2#include <iostream>3void inc_copy(int x) {4 ++x;5 std::cout << x << "\n";6}7 8void inc_ref(int& x) {9 ++x;10}11 12int main() {13 int n = 1;14 inc_copy(n);15 std::cout << n << "\n";16 inc_ref(n);17 std::cout << n << "\n";18}
В main появляется n со значением 1
Вызов выглядит так же, как inc_copy(n): о том, что аргумент изменится, говорит только объявление функции. Поэтому, читая чужой код, смотрите на & в списке параметров.
Вопрос «Чем передача по значению отличается от передачи по ссылке?» часто задают на собеседовании. Короткий ответ: по значению функция получает копию, а по ссылке — саму переменную.
Частая ошибка
В функцию со ссылкой передают число вместо переменной:
void inc_ref(int& x) {
++x;
}
int main() {
inc_ref(5); // ✗
}error: no matching function for call to 'inc_ref'Это ошибка компилятора. Ссылка должна стать другим именем какой-то переменной, а у числа 5 своей переменной нет: увеличивать нечего. Передайте переменную, например inc_ref(n).
Главное
- По значению функция получает копию аргумента; её изменения пропадают вместе с копией.
- Параметр-ссылка
int& x— другое имя переменной вызывающего кода; изменения видны снаружи. - Вызовы
inc_copy(n)иinc_ref(n)выглядят одинаково: разницу показывает только&в объявлении. - В параметр-ссылку
int&можно передать только переменную, а не число вроде5.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.