-1

可能重复:
可以在其范围之外访问局部变量的内存吗?

考虑以下简单的 C++ 代码:

#include <iostream>

struct Test
{
    Test( int i )
        :   ref( i ),
            ptr( &i ) {}

    int &ref;
    int *ptr;
};

int main()
{
    Test t( 5 );

    std::cout << t.ref << std::endl;
    std::cout << *t.ptr << std::endl;

    return 0;
}

Test 类存储了一个指针和一个对位于堆栈上的局部变量 i 的引用。我会假设我在从 Test 构造函数返回后被破坏了。但显然情况并非如此。因为这是程序的输出:

5
134513968

访问指针的结果是我所期望的:每次运行都会更改的随机值。但是引用访问总是导致 5 - 只要局部变量 i 仍然存在。

谁能向我解释这种行为?我在 64 位 Linux(版本 4.6.3)上使用 g++。

问候, enuhtac

4

5 回答 5

6

访问像这样被破坏的变量会导致未定义的行为。打印 5 只是巧合;它可能打印了 -4390843 或者hello world,让你的电脑崩溃,点燃气氛,或者用你的信用卡买披萨。

此外,试图猜测发生了什么真的没有意义,因为编译器可以在生成程序集时对您的代码做一些非常奇怪的事情。这是一个徒劳的练习(但如果你真的想知道所有的比特来自哪里以及它们曾经在哪里,只需调试它)。

于 2012-05-04T20:32:24.610 回答
1

构造时t,您会获得构造期间存储位置的内存地址i。当您调用std::cout << t.ref时,没有理由将该内存位置用于其他用途,因此该值仍然存在。

但是,这不是您可以信任的。i在超出范围后访问该内存位置是未定义的行为。

于 2012-05-04T20:33:41.303 回答
0

不保证会立即删除局部变量。它可以保留在内存中。但这是未定义的行为,而且很危险。

于 2012-05-04T20:33:38.883 回答
0

我没有仔细检查它,但仅仅因为您从堆栈中弹出并不意味着内容被覆盖或更改,该地址中的值保持不变。之后添加更多方法调用,它应该会改变。

于 2012-05-04T20:32:40.350 回答
0

这个答案为您如何思考这个问题提供了一个很好的类比:

你租了一个旅馆房间。你把一本书放在床头柜最上面的抽屉里,然后去睡觉。您第二天早上退房,但“忘记”归还您的钥匙。你偷了钥匙!

一周后,你回到酒店,不办理入住手续,用偷来的钥匙潜入旧房间,然后在抽屉里翻找。你的书还在。惊人!

这个怎么可能?如果您没有租过房间,酒店房间抽屉里的东西是不是无法访问?

于 2012-05-04T20:37:40.540 回答