首页 文章

C中静态的含义

提问于
浏览
4

我以为我对C相当不错,事实证明我不是 . 我问过上一个问题:C++ const lvalue references在其中一个答案中有以下代码:

#include <iostream>
using namespace std; 

 int& GenX(bool reset)
{
    static int* x = new int;
    *x = 100;
    if (reset)
    {
        delete x;
        x = new int;
        *x = 200;
    }
    return *x;
} 

 class YStore
{
public:
    YStore(int& x);
    int& getX() { return my_x; }
private:
    int& my_x;
}; 

 YStore::YStore(int& x)
 : my_x(x)
{
} 

 int main()
{
    YStore Y(GenX(false));
    cout << "X: " << Y.getX() << endl;
    GenX(true); // side-effect in Y
    cout << "X: " << Y.getX() << endl;
    return 0;
}

上面的代码输出X:100,X:200 . 我不懂为什么 . 我玩了一下,并添加了一些输出,即删除x之前的cout;和新的x之后的cout;在复位控制块内 .

我得到的是:删除之前:0x92ee018之后:0x92ee018

所以,我认为静态无声地更新到x,第二个getX正在播放(删除后)未初始化的内存;为了测试这个,我添加了一个x = 0;在删除之后,在新的之前,另一个cout确保x确实被重置为0.这是 .

那么,这里发生了什么?为什么新的返回完全相同的内存块,以前的删除应该是免费的?这只是因为那是操作系统内存管理器决定做的事情,还是我缺少哪些关于静态的特殊内容?

谢谢!

5 回答

  • 8

    我在VC2008中测试你的代码,输出是X:100,X:-17221323 . 我认为原因是静态x被释放 . 我认为我的测试是合理的 .

  • 1

    这正是内存管理员决定做的事情 . 如果你考虑一下,它很有意义:你刚刚释放了一个int,然后你再次要求一个int ...为什么内存管理器不能给你回来你刚刚释放的int?

    从技术上讲,当你在内存管理器附加你释放到空闲列表开头的内存块时,可能会发生什么 . 然后当你调用 new 时,内存管理器会扫描其空闲列表,并在第一个条目中找到一个合适大小的块 .

    有关动态内存分配的详细信息,请参阅"Inside storage allocation" .

  • -1

    至于你的第一个问题:

    X:100,X:200 . 我不懂为什么 .

    由于 Y.my_x 只是 GenXstatic *x 的引用,这正是它应该如何 - 两者都引用了内存中的相同地址,当你更改* x的内容时,会产生副作用 .

  • 1

    这对代码非常有意义 .

    请记住,它是你的指针是静态的,所以当你第二次输入这个函数时你不需要创建一个新的指针,但是当你进入这个函数时,你正在为指针指向一个新的int .

    您也可能处于调试模式,花费更多时间为您提供好的地址 .

    究竟为什么你的指针指向的int在同一个空间中可能只是为了纯粹的运气,那你并没有在它之前声明任何其他变量,所以内存中的相同空间仍然是免费的

  • 1

    您正在访问已解除分配的内存块 . 根据c标准,这是一种未定义的行为,因此任何事情都可能发生 .

    EDIT

    我想我得画画:

    • 为int分配内存,并将堆上分配的对象传递给Y的构造函数,该构造函数将其存储在引用中

    • 然后您释放该内存,但您的对象Y仍然保留对释放的对象的引用

    • 然后再次访问Y对象,该对象包含无效引用,引用已释放的对象,并且您获得的结果是未定义行为的结果 .

    EDIT2

    答案为什么:实现定义 . 编译器可以在任何喜欢的位置创建新对象 .

相关问题