Передача аргументов по значению и по ссылке
Передача аргументов по значению
Аргументы могут передаваться по значению (by value) и по ссылке (by reference). При передаче аргументов по значению внешний объект, который передается в качестве аргумента в функцию, не может быть изменен в этой функции. В функцию передается само значение этого объекта. Например:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
void square(int, int);
int main()
{
int a = 4;
int b = 5;
std::cout << "Before square: a = " << a << "\tb=" << b << std::endl;
square(a, b);
std::cout << "After square: a = " << a << "\tb=" << b << std::endl;
return 0;
}
void square(int a, int b)
{
a = a * a;
b = b * b;
std::cout << "In square: a = " << a << "\tb=" << b << std::endl;
}
Функция square принимает два числа и возводит их в квадрат. В функции main перед и после выполнения функции square происходит вывод на консоль значений переменных a и b, которые передаются в square в качестве аргументов.
И при выполнении мы увидим, что изменения аргументов в функции square действуют только в рамках этой функции. Вне ее значения переменных a и b остаются неизменными:
Before square: a = 4 b = 5
In square: a = 16 b = 25
After square: a = 4 b = 5
Почему так происходит? При компиляции функции для ее параметров выделяются отдельные участки памяти. При вызове функции вычисляются значения аргументов, которые передаются на место параметров. И затем значения аргументов заносятся в эти участки памяти. То есть функция манипулирует копиями значений объектов, а не самими объектами.
Передача параметров по ссылке
При передаче параметров по ссылке передается ссылка на объект, через которую мы можем манипулировать самим объектов, а не просто его значением. Так, перепишем предыдущий пример, используя передачу по ссылке:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
void square(int&, int&);
int main()
{
int a = 4;
int b = 5;
std::cout << "Before square: a = " << a << "\tb=" << b << std::endl;
square(a, b);
std::cout << "After square: a = " << a << "\tb=" << b << std::endl;
return 0;
}
void square(int &a, int &b)
{
a = a * a;
b = b * b;
std::cout << "In square: a = " << a << "\tb=" << b << std::endl;
}
Теперь параметры a и b передаются по ссылке. Ссылочный параметр связывается непосредственно с объектом, поэтому через ссылку можно менять сам объект.
И если мы скомпилируем и запустим программу, то результат будет иным:
Before square: a = 4 b = 5
In square: a = 16 b = 25
After square: a = 16 b = 25
Передача по ссылке позволяет возвратить из функции сразу несколько значений. Также передача параметров по ссылке является более эффективной при передаче очень больших объектов. Поскольку в этом случае не происходит копирования значений, а функция использует сам объект, а не его значение.
От передачи аргументов по ссылке следует отличать передачу ссылок в качестве аргументов:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
void square(int, int);
int main()
{
int a = 4;
int b = 5;
int &aRef = a;
int &bRef = b;
std::cout << "Before square: a = " << a << "\tb=" << b << std::endl;
square(aRef, bRef);
std::cout << "After square: a = " << a << "\tb=" << b << std::endl;
return 0;
}
void square(int a, int b)
{
a = a * a;
b = b * b;
std::cout << "In square: a = " << a << "\tb=" << b << std::endl;
}
Если функция принимает аргументы по значению, то изменение параметров внутри функции также никак не скажется на внешних объектах, даже если при вызове функции в нее передаются ссылки на объекты.
Before square: a = 4 b = 5
In square: a = 16 b = 25
After square: a = 4 b = 5
Передача параметров по значению больше подходит для передачи в функцию небольших объектов, значения которых копируются в определенные участки памяти, которые потом использует функция.
Передача параметров по ссылке больше подходит для передачи в функцию больших объектов, в этом случае не нужно копировать все содержимое объекта в участок памяти, за счет чего увеличивается производительность программы.