堆栈变量生存期好奇的例子

stack variable lifetime curious example

本文关键字:好奇 变量 生存期 堆栈      更新时间:2023-10-16

请考虑这个简单的例子:

#include <iostream>
const int CALLS_N = 3;
int * hackPointer;
void test()
{
    static int callCounter = 0;
    int local = callCounter++;
    hackPointer = &local;
}
int main()
{
    for(int i = 0; i < CALLS_N; i++)
    {
        test();
        std::cout << *hackPointer << "(" << hackPointer << ")";
        std::cout << *hackPointer << "(" << hackPointer << ")";
        std::cout << std::endl;
   }
}

输出(VS2010,MinGW未优化(具有相同的结构:

0(X) Y(X)
1(X) Y(X)
2(X) Y(X)
...
[CALLS_N](X) Y(X)

其中 X - 内存中的某个地址,Y - 一些垃圾号码。
这里所做的是未定义行为的情况。但是,我想了解为什么在当前条件下会有这种行为(并且对于两个编译器来说相当稳定(。
似乎在调用test()之后第一次读取hackPointer会导致有效内存,但第二次连续即时读取会导致垃圾。此外,本地的任何呼叫地址都是相同的。我一直认为堆栈变量的内存在每个函数调用时分配并在返回后释放,但我无法从这个角度解释程序的输出。

">

释放"自动存储不会使内存消失,也不会改变存储在那里的位的模式。它只是使其可供重用,如果您尝试访问曾经存在的对象,则会导致未定义的行为。

从函数返回后,本地占用的内存可能没有被覆盖,因此读取它可能会给出函数中分配的值。

调用另一个函数(在本例中为 operator<<()(后,内存很可能已重用于该函数中的变量,因此可能具有不同的值。

你说得很对,这是未定义的行为。

除此之外,正在发生的事情是std::cout << *hackPointer涉及函数调用:operator<<()在读取*hackPointer的值后被调用。operator<<()很可能使用自己的局部变量,这些变量最终出现在local所在的堆栈上,从而清除后者。