Ответ 1
Вам повезло. Возврат из функции не сразу уничтожит фрейм стека, который вы только что вышли.
Кстати, как вы подтвердили, что получили 6 назад? Выражение std::cout << &i ...
выводит адрес i
, а не его значение.
Посмотрите на код ниже. Я знаю, что он не возвращает адрес локальной переменной, но почему он все еще работает и назначает переменную i
в main() на "6"? Как это только возвращает значение, если переменная была удалена из памяти стека?
#include <iostream>
int& foo()
{
int i = 6;
std::cout << &i << std::endl; //Prints the address of i before return
return i;
}
int main()
{
int i = foo();
std::cout << i << std::endl; //Prints the value
std::cout << &i << std::endl; //Prints the address of i after return
}
Вам повезло. Возврат из функции не сразу уничтожит фрейм стека, который вы только что вышли.
Кстати, как вы подтвердили, что получили 6 назад? Выражение std::cout << &i ...
выводит адрес i
, а не его значение.
Должно быть, что-то делает ваш компилятор.
http://www.learncpp.com/cpp-tutorial/74a-returning-values-by-value-reference-and-address/
Подтверждает, что ваш пример удалит ссылку из памяти стека.
Возвращаемая ссылка или указатель на локальную переменную undefined. undefined поведение означает, что стандарт оставляет решение компилятору. Это означает, что поведение undefined иногда работает хорошо, а иногда это не так.
Адрес i
никогда не изменится в main()
, но содержащееся в нем значение будет. Вы берете ссылку на локальную переменную и используете ее после того, как эта ссылка вышла из сферы действия. (Неточное предупреждение языка) Значение 6
находится в стеке. Поскольку вы не сделали ничего со стеком после того, как вы разместили 6
там, ссылка на него будет по-прежнему содержать одно и то же значение. Итак, как говорили другие, вам повезло.
Чтобы узнать, насколько повезло, попробуйте запустить этот код, который использует стек после вызова foo()
:
#include <iostream>
#include <ctime>
#include <numeric>
int& foo()
{
int i = 6;
std::cout << &i << " = " << i << std::endl; //Prints the address of i before return
return i;
}
long post_foo(int f)
{
srand((unsigned)time(0));
long vals[10] = {0};
size_t num_vals = sizeof(vals)/sizeof(vals[0]);
for( size_t i = 0; i < num_vals; ++i )
{
int r = (rand()%2)+1;
vals[i] = (i+f)*r;
}
long accum = std::accumulate(vals, &vals[num_vals], 0);
return accum * 2;
}
int main()
{
int &i = foo();
// std::cout << "post_foo() = " << post_foo(i) << std::endl;
std::cout << &i << " = " << i << std::endl;
}
Когда я запустил это с вычеркнутым вызовом post_foo()
, 6
все еще находился в стеке, а результат был:
002CF6C8 = 6
002CF6C8 = 6
... но когда я прокомментировал вызов post_foo()
и снова запустил его, 6
был давно ушел:
001FFD38 = 6
post_foo() = 310
001FFD38 = 258923464
Пока ваша функция возвращает целое число по ссылке, она сразу назначается локальной переменной "i" в main(). Это означает, что память стека, выделенная для foo(), должна сохраняться достаточно долго для назначения возврата. Хотя это плохая форма, это обычно работает. Если вы пытались сохранить ссылку
int &i = foo();
было бы гораздо более вероятным сбой.