При возвращении указателя из функции он должен содержать либо значение nullptr, либо адрес, который все еще действителен. Поэтому не следует возвращать из функции адрес автоматической локальной переменной, так как она удаляется после завершения этой функции. Так, рассмотрим следующий некорректный пример функции, которая возвращает большее число из двух:
// пример некорректного возвращения значения int* max(int a, int b) { if (a > b) return &a; else return &b; }
Параметры функции аналогичны переменным - при вызове функции в стеке для них выделяется память. И вданном случае возвращается адрес участка памяти соответствующего параметра
(return &a
или return &b
). Но после возвращения адреса функция завершает свою работу, соответствующие участки памяти очищаются, параметры удаляются, поэтому
возвращенный адрес будет недействительным. И хотя компилятор даже может скомпилировать данную функцию, ограничившись предупреждениями, но такая функция не будет работать корректно.
Тем не менее это не значит, что мы в принципе не можем возвращать указатель из функции. Например, возьмем следующую ситуацию:
#include <iostream> int* max(int*, int*); int main() { int n{5}; int m{4}; int* ptr = max(&n, &m); std::cout << "max: " << *ptr << std::endl; // max: 5 } // пример корректного возвращения значения int* max(int *a, int *b) { if (*a > *b) // разыменовываем указатели return a; else return b; }
Здесь аналогичная функция, которая вычисляет наибольшее из двух чисел, только передаются не сами числа, а адреса переменных. Поэтому возвращенный адрес по прежнему будет действительным.
При этом нам необязательно присваивать результат переменной или константе, можно напрямую обратиться к результату функции:
int main() { int n{5}; int m{4}; std::cout << "max: " << *max(&n, &m) << std::endl; // max: 5 }
Функция также может возвращать ссылку. Однако тут мы можем столкнуться с теми же проблемами, что и при возвращении указателей: не следует возвращать ссылку на локальный объект, который создается внутри функции. Поскольку все создаваемые в функции объекты удаляются после ее завершения, а их память очищается, то возвращаемая ссыла будет указывать на несуществующий объект, как в следующем случае:
// пример некорректного возвращения ссылки int& max(int a, int b) { if (a > b) return a; else return b; }
Здесь функция возвращает ссылку на максимальное значение - один из переданных параметров. Но поскольку память, выделенная для параметров, передаваемых по значению, после выполнения функции очищается, то возвращенная ссылка в итоге будет указывать на несуществующий объект.
Чтобы выйти из ситуации, мы можем передавать значения по ссылке:
#include <iostream> int& max(int&, int&); int main() { int n{5}; int m{4}; int result = max(n, m); std::cout << "max: " << result << std::endl; // max: 5 } // пример корректного возвращения ссылки int& max(int& a, int& b) { if (a > b) return a; else return b; }
Стоит отметить, что если параметры представляют константные ссылки, то чтобы возвратить одну из этих ссылок, функция должна возвращать константную ссылку.
#include <iostream> const int& max(const int&, const int&); int main() { int n{5}; int m{4}; int result = max(n, m); std::cout << "max: " << result << std::endl; // max: 5 } // пример корректного возвращения ссылки const int& max(const int& a, const int& b) { if (a > b) return a; else return b; }