// если указатели адресуют один и тот же массив
if ( src == dst )
return;
// копировать нечего
if ( sz == 0 )
return;
// все еще не закончили?
// тогда самое время что-то сделать
for ( int ix = 0; ix sz; ++ix )
dst[ix] = src[ix];
// явного завершения не требуется
}
Во второй форме инструкции return указывается то значение, которое функция должна вернуть. Это значение может быть сколь угодно сложным выражением, даже содержать вызов функции. В реализации функции factorial(), которую мы рассмотрим в следующем разделе, используется return следующего вида:
return val * factorial(val-1);
В функции, не объявленная с void в качестве типа возвращаемого значения, обязательно использовать вторую форму return, иначе произойдет ошибка компиляции. Хотя компилятор не отвечает за правильность результата, он сможет гарантировать его наличие. Следующая программа не компилируется из-за двух мест, где программа завершается без возврата значения:
// определение интерфейса класса Matrix
#include "Matrix.h"
bool is_equa1( const Matrix ml, const Matrix m2 )
{
/* Если содержимое двух объектов Matrix одинаково,
* возвращаем true;
* в противном случае - false
*/
// сравним количество столбцов
if ( ml.colSize() != m2.co1Size() )
// ошибка: нет возвращаемого значения
return;
// сравним количество строк
if ( ml.rowSize() != m2.rowSize() )
// ошибка: нет возвращаемого значения
return;
// пробежимся по обеим матрицам, пока
// не найдем неравные элементы
for ( int row = 0; row ml.rowSize(); ++row )
for ( int col = 0; co1 ml.colSize(); ++co1 )
if ( ml[row][col] != m2[row][col] )
return false;
// ошибка: нет возвращаемого значения
// для случая равенства
}
Если тип возвращаемого значения не точно соответствует указанному в объявлении функции, то применяется неявное преобразование типов. Если же стандартное приведение невозможно, происходит ошибка компиляции. (Преобразования типов рассматривались в разделе 4.1.4.)
По умолчанию возвращаемое значение передается по значению, т.е. вызывающая функция получает копию результата вычисления выражения, указанного в инструкции return. Например:
Matrix grow( Matrix* p ) {
Matrix val;
// ...
return val;
}
grow() возвращает вызывающей функции копию значения, хранящегося в переменной val.
Такое поведение можно изменить, если объявить, что возвращается указатель или ссылка. При возврате ссылки вызывающая функция получает l-значение для val и потому может модифицировать val или взять ее адрес. Вот как можно объявить, что grow() возвращает ссылку:
Matrix grow( Matrix* p ) {
Matrix *res;
// выделим память для объекта Matrix
// большого размера
// res адресует этот новый объект
// скопируем содержимое *p в *res
return *res;
}
Если возвращается большой объект, то гораздо эффективнее перейти от возврата по значению к использованию ссылки или указателя. В некоторых случаях компилятор может сделать это автоматически. Такая оптимизация получила название именованное возвращаемое значение. (Она описывается в разделе 14.8.)
Объявляя функцию как возвращающую ссылку, программист должен помнить о двух возможных ошибках:
• возврат ссылки на локальный объект, время жизни которого ограничено временем выполнения функции. (О времени жизни локальных объектов речь пойдет в разделе 8.3.) По завершении функции такой ссылке соответствует область памяти, содержащая неопределенное значение. Например:
// ошибка: возврат ссылки на локальный объект
Matrix add( Matrix m1, Matrix m2 )
{
Matrix result:
if ( m1.isZero() )
return m2;
if ( m2.isZero() )
return m1;
// сложим содержимое двух матриц
// ошибка: ссылка на сомнительную область памяти
// после возврата
return result;
}