// pswap() обменивает значения объектов,
// адресуемых указателями vl и v2
void pswap( int *vl, int *v2 ) {
int tmp = *v2;
*v2 = *vl;
*vl = tmp;
}
Функция main() тоже нуждается в модификации. Вместо передачи самих объектов необходимо передавать их адреса:
pswap( i, j );
Теперь программа работает правильно:
Перед swap(): i: 10 j: 20
После swap(): i: 20 j: 10
Альтернативой может стать объявление параметров ссылками. В данном случае реализация swap() выглядит так:
// rswap() обменивает значения объектов,
// на которые ссылаются vl и v2
void rswap( int vl, int v2 ) {
int tmp = v2;
v2 = vl;
vl = tmp;
}
Вызов этой функции из main() аналогичен вызову первоначальной функции swap():
rswap( i, j );
Выполнив программу main(), мы снова получим верный результат.
7.3.1. Параметры-ссылки
Использование ссылок в качестве параметров модифицирует стандартный механизм передачи по значению. При такой передаче функция манипулирует локальными копиями аргументов. Используя параметры-ссылки, она получает l-значения своих аргументов и может изменять их.
В каких случаях применение параметров-ссылок оправданно? Во-первых, тогда, когда без использования ссылок пришлось бы менять типы параметров на указатели (см. приведенную выше функцию swap()). Во-вторых, при необходимости вернуть из функции несколько значений. В-третьих, для передачи большого объекта типа класса. Рассмотрим два последних случая подробнее.
Как пример функции, использующей параметр-ссылку для возврата дополнительного значения, возьмем look_up(), которая будет искать заданную величину в векторе целых чисел. В случае успеха look_up() вернет итератор, указывающий на найденный элемент, иначе – на элемент, расположенный за конечным. Если величина содержится в векторе несколько раз, итератор будет указывать на первое вхождение. Кроме того, дополнительный параметр-ссылка occurs возвращает количество найденных элементов.
#include
// параметр-ссылка 'occurs'
// содержит второе возвращаемое значение
vector::const_iterator look_up(
const vector &vec,
int value, // искомое значение
int &occurs ) // количество вхождений
{
// res_iter инициализируется значением
// следующего за конечным элемента
vector::const_iterator res_iter = vec.end();
occurs = 0;
for ( vector::const_iterator iter = vec.begin();
iter != vec.end();
++iter )
if ( *iter == value )
{
if ( res_iter == vec.end() )
res_iter = iter;
++occurs;
}
return res_iter;
}
Третий случай, когда использование параметра-ссылки может быть полезно, – это большой объект типа класса в качестве аргумента. При передаче по значению объект будет копироваться целиком при каждом вызове функции, что для больших объектов может привести к потере эффективности. Используя параметр-ссылку, функция получает доступ к той области памяти, где размещен сам объект, без создания дополнительной копии. Например:
class Huge { public: double stuff[1000]; };
extern int calc( const Huge & );
int main() {
Huge table[ 1000 ];
// ... инициализация table
int sum = 0;
for ( int ix=0; ix
Может возникнуть желание использовать параметр-ссылку, чтобы избежать создания
копии большого объекта, но в то же время не дать вызываемой функции возможности
изменять значение аргумента. Если параметр-ссылка не должен модифицироваться
внутри функции, то стоит объявить его как ссылку на константу. В такой ситуации
компилятор способен распознать и пресечь попытку непреднамеренного изменения
значения аргумента.
В следующем примере нарушается константность параметра xx функции foo(). Поскольку