Подтвердить что ты не робот

Возврат ссылки на локальную или временную переменную

Посмотрите на код ниже. Я знаю, что он не возвращает адрес локальной переменной, но почему он все еще работает и назначает переменную 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
}
4b9b3361

Ответ 1

Вам повезло. Возврат из функции не сразу уничтожит фрейм стека, который вы только что вышли.

Кстати, как вы подтвердили, что получили 6 назад? Выражение std::cout << &i ... выводит адрес i, а не его значение.

Ответ 3

Возвращаемая ссылка или указатель на локальную переменную undefined. undefined поведение означает, что стандарт оставляет решение компилятору. Это означает, что поведение undefined иногда работает хорошо, а иногда это не так.

Ответ 4

Адрес 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

Ответ 5

Пока ваша функция возвращает целое число по ссылке, она сразу назначается локальной переменной "i" в main(). Это означает, что память стека, выделенная для foo(), должна сохраняться достаточно долго для назначения возврата. Хотя это плохая форма, это обычно работает. Если вы пытались сохранить ссылку

int &i = foo();

было бы гораздо более вероятным сбой.