可以在同一个函数中引用超出范围的局部变量吗?

时间:2014-01-28 20:05:50

标签: c++ pointers scope

在此代码中,我引用了局部变量b,即使它超出了范围。但我是从同一个函数中做到的,所以它可能仍在堆栈中,对吧?我运行程序并且它有效,但我想知道它是否可以保证适用于所有实现。

#include <iostream>

void main()
{
    int* a;
    {
        int b = 5;
        a = &b;
    }
    std::cout << *a;
}

4 个答案:

答案 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