1

В следующем коде показаны две функции. f1() возвращает ссылку инициализированной локальной переменной в области функции, f2() возвращает значение инициализированной локальной переменной в области функций.Возврат ссылки на локальную переменную

Ожидается, что f2() будет хорошо работать, поскольку локально инициализированная переменная. Значение передается из стека в основной.

Ожидается, что f1() не будет работать, потому что ссылка на локальную переменную бесполезна из области действия. Однако для обеих функций выход кажется удовлетворительным.

Вот тестовый код;

#include <iostream> 
using namespace std; 

// function declarations 
int& f1(); 
int f2(); 

int main() 
{ 
    cout << "f1: " << f1() << endl; // should not work! 
    cout << "f2: " << f2() << endl; // should work 

    return 0; 
} 

int& f1()  // returns reference 
{ 
    int i = 10; // local variable 

    return i; // returns reference 
} 

int f2()  // returns value 
{ 
    int i = 5; // local variable 

    return i; // returns value 
} 

Выход следующий:

f1: 10 
f2: 5 

Почему f1() работает нормально даже в том случае, если f1() возвращает ссылку на локальную переменную?

+5

Потому что вы вызываете неопределенное поведение и делаете так, что небо - предел. – 101010

+0

Потому что вам было ужасно повезло ... – Chiel

+0

Что вы ожидали? – emlai

ответ

5

undefined поведение!

Это то, что вы делаете. Вы получаете доступ к переменной, которая вышла за рамки. Однако может случиться так, что система ничего не написала над значением, которое уже было там, что объясняет поведение.

Вот почему найти такие логические ошибки в реальном коде сложно. Потому что вам может быть (un) повезло, и переменная имеет правильное значение (в этом конкретном исполнении).

Таким образом, возвращаемое значение f1() является ссылкой на то, что вышло за пределы области действия, а возвращаемое значение f2() - это копия локальной переменной этой функции, которая в порядке.


Однако спуск компилятор должен предупредить вас об этом, с предупреждением такого рода:

предупреждение: ссылка на локальную переменную «я» вернулся [-Wreturn-местный-адр]

Включите свои предупреждающие флажки в вашем компиляторе. :)

7

Доступ к локальной переменной из области действия является неопределенным поведением. Неопределенное поведение означает, что программа может работать, она может segfault, она может печатать значения мусора, все.

Причина низкого уровня , поскольку локальные переменные расположены в стеке. Стек принадлежит доступному для записи адресуемому пространству процесса (по крайней мере, на большинстве, если не всех, таких ОС, как ваш). Программа может писать в нее так, как она хочет. Однако, запись в стек - это то, что не поддерживается C++. C++ определяет только локальные переменные, а не фреймы вызовов или обратные адреса. Он находится на более высоком уровне абстракции. Единственный язык, поддерживающий запись непосредственно в стек, который я знаю, - Assembly.


Эта причина не указана в стандарте C++ любыми средствами.