可以在同一函数中引用副本本地变量是否可以



在此代码中,即使它不超出范围,我也会引用本地变量b。但是我从同一函数中进行操作,所以它可能仍在堆栈上,对吗?我运行了该程序,但我想知道它是否可以保证在所有实施方面工作。

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

no,那是不保证工作的a一旦退出了内部范围,就会悬空,因此对它的任何解雇都会导致不确定的行为,而没有任何保证。

这里的问题不是 b不超出范围b lifetime 已经结束。范围是关于对象的名称的范围。生命周期是关于对象存在(在计算模型中)。

从技术上讲,当您使用*a引用它时,对象b不存在。用来代表它的字节可能恰好在内存中仍未变化,并且有时使用*a访问它们可能会正常工作,尤其是在未打开优化的情况下,但这是未定义的行为。

即使其名称不在范围中,仍然可以访问一个对象。这是一个对象在其一生中可访问的示例,即使它不在范围中:

void foo(void)
{
    int b;
    bar(&b);
}

在此代码中,函数bar可以访问b,即使它在foo中看不到b的名称。尽管Control离开创建b的块,但块的执行仅被暂停而不是终止。因此,即使函数bar执行,b仍然存在。因此,b将不在范围内,但访问将在其寿命中。

规格说

每个对象的实例具有自动存储持续时间(3.7.3)与每个条目中的块相关联。这样的对象存在并保留其在块执行期间的最后存储值,而块被暂停(通过函数或接收信号的呼叫)。

b是具有自动存储持续时间的对象。因此,当您在对象的块外面时,对象不再存在。我相信,您 can 跳跃之前,请继续写信,但如果您跳出其块,则不会。这太伸展了。

我组合了这个示例,以帮助证明基于典型的基于帧的堆栈中的内存分配发生了什么。请参阅:当堆栈变量超出范围时是否会划分?这个问题被重复地关闭。

testerA中,我们捕获了 local 变量a的地址,以供将来使用。我们对testerB做了类似的操作,只有这次,我们捕获了 second 整数变量的地址, b。请注意,我们用值44覆盖a的内存 - 在此功能中称其为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

最新更新