请看下面的代码。我知道它不返回局部变量的地址,但为什么它仍然有效并将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
}
答案 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)
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
答案 4 :(得分:1)
当你的函数通过引用返回一个整数时,它立即被赋值给main()中的局部变量'i'。这意味着为foo()分配的堆栈内存必须持续足够长的时间才能进行返回分配。虽然形状不好,但这通常有效。如果您曾尝试保留参考
int &i = foo();
它更有可能失败。