返回一个本地或临时variables的引用
看下面的代码。 我知道它不会返回局部variables的地址,但为什么它仍然工作,并将variablesi
在main()中分配到“6”? 如果从堆栈内存中删除variables,它是如何返回值的?
#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 }
你好幸运啊。 从函数返回不会立即清除刚才退出的堆栈框架。
顺便说一句,你怎么确认你有6回? expression式std::cout << &i ...
打印std::cout << &i ...
的地址,而不是它的值。
必须是你的编译器正在做的事情。
http://www.learncpp.com/cpp-tutorial/74a-returning-values-by-value-reference-and-address/
确认您的示例将从堆栈内存中删除引用。
返回引用或指向局部variables的指针是未定义的行为。 未定义的行为意味着,标准将决定留给编译器。 这意味着,未定义的行为有时效果不错, 有时不行 。
i
的地址永远不会在main()
改变,但是其中包含的值将会被改变。 你引用了一个局部variables,并在引用超出范围之后使用它。 (不精确的语言警告)值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
当你的函数通过引用返回一个整数时,它立即被分配给main()中的局部variables'i'。 这意味着分配给foo()的堆栈内存必须足够长才能返回赋值。 虽然这是不好的forms,这通常是有效的。 如果你曾试图保留一个参考
int &i = foo();
它会更有可能失败。