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() 也能正常工作?

4

2 回答 2

7

访问范围外的局部变量是未定义的行为。未定义的行为意味着程序可能会工作,可能会出现段错误,可能会打印垃圾值,一切。

底层原因1是局部变量位于堆栈上。堆栈属于进程的可写地址空间(至少在大多数(如果不是全部)像您这样的操作系统上)。程序可能会随心所欲地对其进行写入。但是,写入堆栈是 C++ 不支持的。C++ 只定义局部变量,不定义调用帧或返回地址。它位于更高的抽象级别。我所知道的唯一支持直接写入堆栈的语言是汇编。


1 C++ 标准未以任何方式指定此原因。

于 2015-10-20T11:16:48.937 回答
5

欢迎来到未定义的行为

这就是你正在做的事情。您访问了一个超出范围的变量。但是,可能是系统没有在已经存在的值上写一些东西,这解释了这种行为。

这就是为什么很难在实际代码中发现这样的逻辑错误。因为您可能(不)幸运并且变量具有正确的值(在该特定执行中)。

所以,f1()的返回值是对超出范围的东西的引用,而f2()的返回值是该函数的局部变量的副本,这没关系。


但是,下降编译器应该警告您这一点,并发出以下警告:

警告:对局部变量“i”的引用返回 [-Wreturn-local-addr]

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

于 2015-10-20T11:19:37.073 回答