1

我有一段代码正在创建基于图块的关卡。

class Level {

//Variables
//===================================================
public:
    Tile *** TileGrid;  //A 2d array of pointers to tiles
    int TilesWide, TilesTall;

//Methods
//===================================================
public:
    Level::Level(char * fileName);
    Level::~Level();
    void Draw();
};

我为 TileGrid 分配内存,一切都很好。我也为班级设置了析构函数。

Level::~Level() {

    for (int i = 0; i < TilesTall; i++) {
        for (int j = 0; j < TilesWide; j++)
            //delete the looped tile being pointed to
            delete TileGrid[i][j];

        //delete the row
        delete [] TileGrid[i];
    }

    //delete the array of rows
    delete [] TileGrid;
}

为了咯咯笑,我决定删除我的 Level 实例。这样做之后,我发现我仍然可以调用它的 Draw 方法。

在调试器中,TilesWide 和 TilesTall 的值是一个巨大的负数,所以在我的 for 循环中没有任何东西会迭代网格。

尝试访问已删除的变量不会导致某种崩溃吗?

4

4 回答 4

2

不一定会导致崩溃。它可能会,也可能不会。它会导致所谓的未定义行为


本国际标准未强加要求的未定义行为行为

它可能会像毁灭宇宙一样崩溃。

于 2013-02-13T20:18:43.987 回答
2

可能导致崩溃。这取决于该内存是否被另一个对象覆盖和/或内存系统是否将该页面重新分配给另一个进程(或从当前进程中释放该页面)。底线是你不能依赖它工作(你已经知道了)

于 2013-02-13T20:19:05.767 回答
1

删除后访问对象是未定义的行为。未定义的行为可能意味着任何事情,从“看似成功”到“崩溃”再到“格式化硬盘”。

于 2013-02-13T20:19:12.427 回答
1

您所做的被称为“未定义的行为”。

未定义的行为并不意味着“会崩溃”,它意味着任何事情都可能发生。该程序可以格式化你的硬盘,它可以演奏一首巴赫奏鸣曲,它可以在屏幕上绘制一张达菲鸭的图片,它可以给你一个负值,而且在任何情况下它都会是所要求的。

不崩溃包括在内,崩溃也是如此。

现在让我们假设一个合理的 C++ 实现。该方法Level::Draw不会随着Level您传递它的实例而变化,因此您调用的函数不依赖于实例。该实例作为一个参数传递给该函数,作为一个指针,该指针指向堆中的某个内存,该内存曾经是该变量的副本。从那时起,它已经被回收用于其他目的,或者可能包含有关堆的簿记信息——什么是未定义的。(并且,如果运行时将页面返回给系统,访问它可能会出现段错误)

然后,您继续将该垃圾解释为一些值。一切都很好,因为随机垃圾int在大多数系统上几乎总是看起来像 C++ eger(在这种情况下,作为负整数)。

现在,一旦您开始取消引用指针(并因此访问内存的“随机”部分)或写入 的状态this,可能会发生崩溃(如果不是那时,那么稍后或其他地方)。

于 2013-02-13T20:22:02.113 回答