Возвращаемые значения функции ссылочного типа
Функции можно объявить, чтобы они возвращали ссылочный тип. Существует две причины создания такого объявления.
- Возвращаемая информация представляет собой настолько крупный объект, что возврат ссылки является более эффективным, чем возврат копии.
- Тип функции должен представлять собой l-значение.
- Объект, на который указывает ссылка, не выйдет из области видимости при возврате управления функцией.
Так же, как это может быть более эффективным для передачи больших объектов в функции по ссылке, он также может быть более эффективным для возврата больших объектов из функций по ссылке. Протокол возврата ссылок устраняет необходимость копировать объект во временное хранилище перед возвратом.
Типы возврата ссылок также могут оказаться полезными, если результатом функции должно быть l-значение. Большинство перегруженных операторов относятся к этой категории, в частности оператор присваивания. Перегруженные операторы рассматриваются в перегруженных операторах.
Пример
Рассмотрим пример Point .
// refType_function_returns.cpp // compile with: /EHsc #include using namespace std; class Point < public: // Define "accessor" functions as // reference types. unsigned& x(); unsigned& y(); private: // Note that these are declared at class scope: unsigned obj_x; unsigned obj_y; >; unsigned& Point :: x() < return obj_x; >unsigned& Point :: y() < return obj_y; >int main() < Point ThePoint; // Use x() and y() as l-values. ThePoint.x() = 7; ThePoint.y() = 9; // Use x() and y() as r-values. cout
Выходные данные
x = 7 y = 9
Обратите внимание, что функции x и y объявляются как типы возвращаемых ссылок. Эти функции можно использовать на любой стороне оператора присваивания.
Также обратите внимание, что в функции main объект ThePoint остается в области видимости, поэтому его ссылочные элементы продолжают действовать, и к ним можно получить безопасный доступ.
Объявления ссылочных типов должны содержать инициализаторы. Исключение составляют следующие случаи.
- Явное extern объявление
- Объявление члена класса
- Объявление в классе
- Объявление аргумента в адрес функции или типа возвращаемого значения для функции
Предупреждение при возвращении адреса локальной переменной
Если объект объявляется в локальной области видимости, он будет уничтожен, когда функция вернет ссылку. Возвращенная этому объекту ссылка может нарушить доступ в среде выполнения, поскольку вызывающий объект попытается использовать пустую ссылку.
// C4172 means Don't do this. Foo& GetFoo() < Foo f; . return f; >// f is destroyed here
Компилятор выдает предупреждение в этом случае: warning C4172: returning address of local variable or temporary В простых программах доступ может случайно сохраниться, если ссылка будет использована вызывающим объектом до перезаписи соответствующей области памяти. Однако это чистая случайность. Обратите внимание на предупреждение.
Как вернуть ссылку на объект c
При возвращении указателя из функции он должен содержать либо значение nullptr , либо адрес, который все еще действителен. Поэтому не следует возвращать из функции адрес автоматической локальной переменной, так как она удаляется после завершения этой функции. Так, рассмотрим следующий некорректный пример функции, которая возвращает большее число из двух:
// пример некорректного возвращения значения int* max(int a, int b) < if (a >b) return &a; else return &b; >
Параметры функции аналогичны переменным - при вызове функции в стеке для них выделяется память. И вданном случае возвращается адрес участка памяти соответствующего параметра ( return &a или return &b ). Но после возвращения адреса функция завершает свою работу, соответствующие участки памяти очищаются, параметры удаляются, поэтому возвращенный адрес будет недействительным. И хотя компилятор даже может скомпилировать данную функцию, ограничившись предупреждениями, но такая функция не будет работать корректно.
Тем не менее это не значит, что мы в принципе не можем возвращать указатель из функции. Например, возьмем следующую ситуацию:
#include int* max(int*, int*); int main() < int n; int m; int* ptr = max(&n, &m); std::cout // пример корректного возвращения значения int* max(int *a, int *b) < if (*a >*b) // разыменовываем указатели return a; else return b; >
Здесь аналогичная функция, которая вычисляет наибольшее из двух чисел, только передаются не сами числа, а адреса переменных. Поэтому возвращенный адрес по прежнему будет действительным.
При этом нам необязательно присваивать результат переменной или константе, можно напрямую обратиться к результату функции:
int main() < int n; int m; std::cout
Возвращение ссылки
Функция также может возвращать ссылку. Однако тут мы можем столкнуться с теми же проблемами, что и при возвращении указателей: не следует возвращать ссылку на локальный объект, который создается внутри функции. Поскольку все создаваемые в функции объекты удаляются после ее завершения, а их память очищается, то возвращаемая ссыла будет указывать на несуществующий объект, как в следующем случае:
// пример некорректного возвращения ссылки int& max(int a, int b) < if (a >b) return a; else return b; >
Здесь функция возвращает ссылку на максимальное значение - один из переданных параметров. Но поскольку память, выделенная для параметров, передаваемых по значению, после выполнения функции очищается, то возвращенная ссылка в итоге будет указывать на несуществующий объект.
Чтобы выйти из ситуации, мы можем передавать значения по ссылке:
#include int& max(int&, int&); int main() < int n; int m; int result = max(n, m); std::cout // пример корректного возвращения ссылки int& max(int& a, int& b) < if (a >b) return a; else return b; >
Стоит отметить, что если параметры представляют константные ссылки, то чтобы возвратить одну из этих ссылок, функция должна возвращать константную ссылку.
#include const int& max(const int&, const int&); int main() < int n; int m; int result = max(n, m); std::cout // пример корректного возвращения ссылки const int& max(const int& a, const int& b) < if (a >b) return a; else return b; >
Как вернуть ссылку на объект?
Здравствуйте!
Стоит задача применения сразу двух методов к одному объекту класса. Например, имеется объект с класса Complex. Необходимо, чтобы подобная конструкция работала корректно: c.sum(a).sub(b). Как я понимаю, необходимо, чтобы метод sum возвращал ссылку на объект, чтобы второй метод корректно применился.
Прошу пояснить как это сделать. Возможно ли это реализовать без помощи создания временного объекта, то есть вернуть сразу ссылку на обновленный объект c?
- Вопрос задан более трёх лет назад
- 654 просмотра
3 комментария
Простой 3 комментария
Возврат ссылок
Функция может возвращать ссылку. В результате такая функция может использоваться в левой части оператора присваивания. В качестве примера рассмотрим следующую простую программу:
#include
char &replace(int i) ; // возврат ссылки
char s [80] = "Hello There";
int main()
replace(5) = 'X'; // присвоение X пробелу после Hello
cout return 0;
>
char &replace(int i)
return s [ i ];
>
Эта программа заменяет пробел между словами «Hello» и «There» символом «X». В результате программа выводит на экран «HelloXThere».
Функция replace() в соответствии со своим объявлением возвращает ссылку на символьный массив. В соответствии со своей реализацией функция replace() возвращает ссылку на элемент массива s, определяющийся аргументом i. Далее возвращаемая функцией replace() ссылка используется функцией main() для присвоения элементу буквы «X».