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

欢迎来到未定义的行为

这就是你正在做的。你访问一个超出范围的变量。但是,这可能是因为系统没有写入已经存在的值,这解释了行为。

这就是为什么在真实代码中找到这样的逻辑错误很难。因为你可能(非)幸运,并且变量具有正确的值(在该特定执行中)。

因此,f1()的返回值是对超出范围的东西的引用,而f2()的返回值是该函数的局部变量的副本,这是正确的。


然而,血统编译器应该提醒你注意这一点,与这样的警告:

警告:引用局部变量“我”返回[-Wreturn-本地地址]

请在您的编译器中启用您的警告标志。 :)

7

访问超出范围的局部变量是未定义的行为。未定义的行为意味着程序可能工作,它可能会出现段错误,它可能会打印垃圾值和所有内容。

低级原因因为这是局部变量位于堆栈上。堆栈属于进程的可写地址空间(至少在大多数情况下,如果不是全部的话,就像你的那样)。该程序可能会写入它就像它想。 然而,,写入堆栈是C++不支持的东西。 C++只定义局部变量,而不是调用帧或返回地址。它驻留在更高层次的抽象中。支持直接写入堆栈的唯一语言是Assembly。


其理由没有被以任何方式的C++标准指定。