返回对本地或临时变量的引用

时间:2010-04-30 11:52:22

标签: c++

请看下面的代码。我知道它不返回局部变量的地址,但为什么它仍然有效并将main()中的变量i分配给'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
}

5 个答案:

答案 0 :(得分:23)

你很幸运。从函数返回不会立即擦除刚刚退出的堆栈帧。

顺便说一句,你是怎么证实你有6回来的?表达式std::cout << &i ...打印i的地址,而不是其值。

答案 1 :(得分:3)

必须是编译器正在做的事情。

http://www.learncpp.com/cpp-tutorial/74a-returning-values-by-value-reference-and-address/

确认您的示例将从堆栈内存中删除引用。

答案 2 :(得分:3)

返回引用或指向局部变量的指针是未定义的行为。未定义的行为意味着,标准将决策留给编译器。这意味着,未定义的行为有时效果很好,sometimes it doesn't

答案 3 :(得分:2)

imain()的地址永远不会改变,但其中包含的值将会改变。您正在引用局部变量并在该引用超出范围之后使用它。 (不精确的语言警告)值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

答案 4 :(得分:1)

当你的函数通过引用返回一个整数时,它立即被赋值给main()中的局部变量'i'。这意味着为foo()分配的堆栈内存必须持续足够长的时间才能进行返回分配。虽然形状不好,但这通常有效。如果您曾尝试保留参考

int &i = foo();

它更有可能失败。