在此代码中,我引用了局部变量b
,即使它超出了范围。但我是从同一个函数中做到的,所以它可能仍在堆栈中,对吧?我运行程序并且它有效,但我想知道它是否可以保证适用于所有实现。
#include <iostream>
void main()
{
int* a;
{
int b = 5;
a = &b;
}
std::cout << *a;
}
答案 0 :(得分:10)
不,不保证可以正常工作。一旦内部范围退出,a
就会悬空,因此任何取消引用它都会导致未定义的行为,并且不会保证任何内容。
答案 1 :(得分:7)
此处的问题不是b
超出范围。 b
的生命周期已经结束。范围是关于对象的名称的已知位置。生命周期是指对象存在(在计算模型中)。
从技术上讲,当您使用b
引用它时,对象*a
不存在。用于表示它的字节可能恰好在内存中保持不变,并且使用*a
访问它们有时可能会起作用,特别是如果未打开优化,但它是未定义的行为。
即使对象的名称不在范围内,仍然可以访问该对象。下面是一个在其生命周期内可访问的对象的示例,即使它不在范围内:
void foo(void)
{
int b;
bar(&b);
}
在此代码中,函数bar
可以访问b
,即使它在b
中看不到foo
的名称。虽然控制离开了创建b
的块,但块的执行仅暂停,而不是终止。因此即使函数b
正在执行,bar
仍然存在。因此b
将超出范围,但访问将在其生命周期内进行。
答案 2 :(得分:2)
规范说
具有自动存储持续时间(3.7.3)的每个对象的实例与其块中的每个条目相关联。这样的对象在块的执行期间存在并保留其最后存储的值,并且当块被暂停时(通过调用函数或接收信号)。
b
是具有自动存储持续时间的对象。因此,当您在对象块之外时,该对象不再存在。 可以 在之前跳转并继续写入它,我相信,但是如果你跳到它的块之外就没有了。这太过于拉伸了它。
答案 3 :(得分:0)
我整理了这个示例,以帮助演示典型的基于帧的堆栈中的内存分配情况。请参阅:Is the stack variable deallocated when it goes out of scope?。这个问题被重复了。
在testerA
中,我们捕获了 local 变量a
的地址,以备将来使用。我们用testerB
做类似的事情,只是这次我们捕获 second 整数变量b
的地址。请注意,我们用值a
覆盖了44
的内存-在此函数中调用了f
。
您可以在调用函数后立即检查这些值,以观察发生了什么情况。我们实际上是在重复使用相同的内存地址-但不能保证先前函数调用中的数据采用哪种格式。
#include <iostream>
int* aPtr = nullptr;
int* bPtr = nullptr;
int testerA()
{
int a = 3;
aPtr = &a;
}
int testerB()
{
int f = 44;
int b = 5;
bPtr = &b;
}
int main()
{
using namespace std;
testerA();
int test1 = *aPtr;
testerB();
int test2 = *aPtr;
int test3 = *bPtr;
cout << "A: " << test1 << " -> " << test2 << endl;
cout << "B: " << test3 << endl;
cout << "aPtr: " << hex << aPtr << endl;
cout << "bPtr: " << hex << bPtr << endl;
return 0;
}
A: 3 -> 44
B: 5
aPtr: 0x7fff9e58609c
bPtr: 0x7fff9e586098