Можно ли таким образом возвращать локальный указатель из функции?
В книге С. Прата наткнулся на пример:
struct free_throws {
int made;
int attempts;
double percent;
};
const free_throws & clone(free_throws &ft) {
free_throws *pt;
pt = &ft;
return *pt;
}
Насколько я понимаю нельзя возвращать локальные переменные по ссылке или по адресу, потому что они уничтожатся по окончанию функции и вернется ссылка на уже несуществующую переменную, т.е. на "мусор".
Вопрос: можно ли так возвращать локальную переменную-указатель? Почему?
Ответы (2 шт):
Давайте посмотрим, что у вас получается...
const free_throws & clone(free_throws &ft) {
Вы передаете функции ссылку на lvalue - на некий объект за пределами функции.
free_throws *pt;
pt = &ft;
return *pt;
И по сути возвращаете его. Т.е. можно было просто написать -
return ft;
Т.е. вы вернули ссылку на тот же объект, который и передали, только как на константный. Так что возвращать-то можно, а смысл?
Я тут - https://ideone.com/5fSQqc - немного упростил в смысле типов, и убрал константность - как видите, clone() возвращает просто то, что ей передали. Скажем так - никакого клонирования при этом не происходит.
Вот если бы вы сделали так:
const free_throws & clone(free_throws ft) {
это уже был бы возврат ссылки на локальную переменную (переданную в функцию копию) - тут дело другое.
У вас по ссылке заходит объект и потом вы берете от него адрес. Это равносильно тому, что как будто вы не находясь в функции, а просто взяли адрес у объекта, не передавая его в функцию, так как ссылка это просто второе имя (псевдоним) на тот же самый объект. То есть внутри функции мы имеем дело с тем же самым объектом, что и существовал до того, как его передали в функцию. Поэтому взятие адреса внутри функции это тоже самое, что взятие адреса на него и вне функции. Потом вы разыменовываете этот указатель и попадаете на адрес объекта, то есть это равносильно тому, что вы просто бы обратились к объекту, что находится до захода в функцию. и потом возвращаете этот объект по ссылке наружу, то есть это равносильно тому, что вы и не пробрасывали вовсе объект в функцию, а просто создали ссылку на объект напрямую. Вы не вернули указатель или ссылку на локальную переменную, вы вернули ссылку на тот объект, что заходил в функцию сверху, то есть который существовал и до того, как вызвалась функция. Но есть один ньюанс. Если бы функция принимала бы константную ссылку (говоря более правильно - ссылку на константный объект), то вы могли бы тогда принять и временный объект (так как константная ссылка биндится к rvalue) и вот тогда возврат ссылки на него из функции был бы опасен, так как ссылка бы существовала после завершения функции, а временный объект, что заходил сверху в функцию к тому времени перестал бы существовать.