Выбрать главу

#include iostream

void swap( int, int );

int main() {

int i = 10;

int j = 20;

cout "Перед swap():\ti: "

i "\tj: " j endl;

swap( i, j );

cout "После swap():\ti: "

i "\tj: " j endl;

return 0;

}

Результат выполнения программы:

Перед swap(): i: 10 j: 20

После swap(): i: 10 j: 20

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

// 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

Может возникнуть желание использовать параметр-ссылку, чтобы избежать создания

копии большого объекта, но в то же время не дать вызываемой функции возможности

изменять значение аргумента. Если параметр-ссылка не должен модифицироваться

внутри функции, то стоит объявить его как ссылку на константу. В такой ситуации

компилятор способен распознать и пресечь попытку непреднамеренного изменения

значения аргумента.