【问题标题】:Returning a reference to a local or temporary variable [duplicate]返回对局部或临时变量的引用[重复]
【发布时间】:2011-02-14 05:09:14
【问题描述】:

看看下面的代码。我知道它不会返回局部变量的地址,但是为什么它仍然可以工作并将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
}

【问题讨论】:

  • 你很幸运。不要这样做。
  • 您可能会发现这很有用:stackoverflow.com/questions/6441218/…
  • 我相信有些运气是因为 i 在 foo() 中没有改变(它允许编译器放置在文本或长期存在的地方而不是堆栈中)
  • 从局部变量获取地址可能会阻止编译器/运行时为其使用寄存器。结果表现不佳。

标签: c++


【解决方案1】:

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

顺便说一句,你是如何确认你得到了 6 的?表达式std::cout &lt;&lt; &amp;i ... 打印的是i 的地址,而不是它的值。

【讨论】:

  • 当他在 main() 中打印出 6 时。
  • @San:嗯,现在@Dave18 编辑了这个问题。
  • 对不起,我一定已经阅读了这之后的问题:)
  • 还有一点,函数调用的后果取决于编译器。通常 GCC 不会修改堆栈上的任何值(因此,我们仍然获得旧值)。然而,像 Dev C++ 这样的编译器会修改这些值(尽管我看不出这样做的原因),如果您稍后尝试访问任何值,您只会得到一个垃圾值!
  • @smartmuki:好点!此外,我相信调试编译有时会在退出时对堆栈进行平衡,以突出对范围外变量的访问。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 而且效果不佳的几率取决于观看演示的人的重要性。
    【解决方案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】:

      虽然您的函数通过引用返回一个整数,但它会立即分配给 main() 中的局部变量“i”。这意味着为 foo() 分配的堆栈内存必须保持足够长的时间才能返回分配。虽然它的形式不好,但这通常有效。如果您尝试保留参考文献

      int &i = foo();
      

      失败的可能性更大。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-19
        • 1970-01-01
        • 2011-04-13
        • 1970-01-01
        • 1970-01-01
        • 2022-01-17
        相关资源
        最近更新 更多