Перейти к содержимому
Теория · Функции · урок 2 из 13

Параметры: по значению и по ссылке

Представьте, что вы отдаёте коллеге документ на правку. Можно отдать ксерокопию: коллега исчеркает её, а ваш оригинал останется чистым. А можно отдать сам оригинал, и тогда все правки окажутся у вас. Функция в C++ тоже получает аргумент одним из этих двух способов, и по вызову разницу не видно.

Функция inc_copy увеличивает свой параметр на единицу, но переменная, переданная в неё, от этого не меняется:

C++
#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) по шагам:

  1. Создаётся новая переменная x, и в неё копируется значение аргумента n, то есть 1.
  2. ++x увеличивает копию до 2, и функция печатает 2.
  3. Функция заканчивается, и x исчезает вместе со всеми изменениями.
  4. main печатает n, а n всё ещё равна 1.

Это передача по значению: функция работает с ксерокопией, а не с самой n. Аналогия хромает в одном: копию нельзя унести с собой, она живёт только до конца функции.

Изменённую копию можно вернуть через return: вызывающий код получит новое значение, а исходная переменная останется прежней.

Параметр-ссылка

Чтобы функция меняла переменную вызывающего кода, параметр объявляют ссылкой: после типа ставят &. Ссылка — другое имя уже существующей переменной, а не её копия. Это как прозвище: «Саша» и «Александр» — один и тот же человек.

C++
#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 из 8 · рамок: 1

В main появляется n со значением 1

Следите за n в рамке main

Вызов выглядит так же, как inc_copy(n): о том, что аргумент изменится, говорит только объявление функции. Поэтому, читая чужой код, смотрите на & в списке параметров.

Вопрос «Чем передача по значению отличается от передачи по ссылке?» часто задают на собеседовании. Короткий ответ: по значению функция получает копию, а по ссылке — саму переменную.

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

В функцию со ссылкой передают число вместо переменной:

C++
void inc_ref(int& x) {
    ++x;
}

int main() {
    inc_ref(5);  // ✗
}
TEXT
error: no matching function for call to 'inc_ref'

Это ошибка компилятора. Ссылка должна стать другим именем какой-то переменной, а у числа 5 своей переменной нет: увеличивать нечего. Передайте переменную, например inc_ref(n).

Главное

  • По значению функция получает копию аргумента; её изменения пропадают вместе с копией.
  • Параметр-ссылка int& x — другое имя переменной вызывающего кода; изменения видны снаружи.
  • Вызовы inc_copy(n) и inc_ref(n) выглядят одинаково: разницу показывает только & в объявлении.
  • В параметр-ссылку int& можно передать только переменную, а не число вроде 5.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом