这会导致内存泄漏吗?

Kee*_*elx 0 c++ memory pointers memory-leaks allocation

好吧,所以我和其他人有些分歧,我希望有人比我们中的任何一个人都更了解c ++可以解决这个问题.假设我们在函数内部的某个代码块(对于tilemap引擎):

void loadTiles()
{
Tile* tile = new Tile();
Level->addTile(x, y, tile); //x and y are just arbitrary ints.
/* when addTile is called, it fills the values of the chunk of memory pointed to by tile to the predefined chunk of memory created in the Level object. */
//Then, to remove the dangling pointer safely,
tile = NULL;
} //Then the actual memory pointed to by tile is deallocated here.
Run Code Online (Sandbox Code Playgroud)

Level类有一个名为map [] []的2D Tile数组,它的addTile函数看起来完全像这样:

void Level::addTile(int x, int y, Tile *tile) 
{
    map[x][y] = tile;
}
Run Code Online (Sandbox Code Playgroud)

指向tile的内存被释放,指针不再指向不存在的对象,tile对象的值基本上被复制到Level对象的map [] []数组中.我是对的,还是我弄错了?另一个人争辩说这会导致内存泄漏.

Dav*_*son 8

让我们看看每段代码.

1)分配内存

Tile* tile = new Tile();
Run Code Online (Sandbox Code Playgroud)

这将在堆上创建一个新的Tile对象,并将内存地址存储在变量tile中.请记住,变量tile只是一个指针,而不是对象本身.

2)复制参考

void Level::addTile(int x, int y, Tile *tile) { map[x][y] = tile;}
Run Code Online (Sandbox Code Playgroud)

上述函数只需一个指针并将其保存到一个多维数组中以备将来使用.在列出的所有代码的上下文中,现在将有两个对象的引用...原始调用函数中的tile*和多维数组中的条目.再次,请记住这些是指针(只有4个字节,具体取决于您的系统架构).

3)将指针设置为NULL

tile = NULL;
Run Code Online (Sandbox Code Playgroud)

此代码的结果是指针变量tile将不再指向堆上创建的对象.但是,该对象仍然存在.此时,在所有代码的上下文中,由于map [] []数组,您仍然会有一个指向对象的指针.

实际上,您不需要这行代码.tile不是悬空指针,因为它指向一个有效对象(在将其设置为NULL之前).代码也不会破坏对象.由于tile是局部变量,因此当函数范围退出时它将被清除.只清理指针,而不是它指向的对象.在此方案中将其设置为NULL可实现除废物循环之外的极少数.

每个说法也不是内存泄漏.您仍然有一个指向map [] []数组中对象的有效指针,因此您始终可以使用该引用来清理内存.

4)你需要做什么

您需要在某处删除该对象.在C++中,这是delete关键字.

delete tile;
Run Code Online (Sandbox Code Playgroud)

要么

delete map[x][y];
Run Code Online (Sandbox Code Playgroud)

现在,请记住,一旦上面的代码运行,堆上的内存将被释放回操作系统,您的应用程序将无法再安全地访问内存.因此,对map [x] [y] - > {SomeMethod}的任何调用都将导致访问冲突异常.存储在map [x] [y]中的指针现在是一个悬空指针(它指向一个对该类型无效的内存地址).

如果您需要在销毁关卡之前从关卡地图中删除关卡,您可以执行以下操作:

void Level::deleteTile(int x, int y) 
{ 
    if (map[x][y] != NULL)
    {
        delete map[x][y];
        map[x][y] = NULL;
     }
}
Run Code Online (Sandbox Code Playgroud)

我还会将addTile方法更改为:

void Level::addTile(int x, int y, Tile *tile)
{
    deleteTile(x, y);
    map[x][y] = tile;
}
Run Code Online (Sandbox Code Playgroud)

最后,当你破坏Level对象时,你需要做这样的事情:

void ~Level()
{
    for (int i; i<MaxX; i++)
    {
        for (int j; j<MaxY; j++)
        {
            delete map[i][j];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在创建Level对象时,应该将map [] []数组清零,以便所有值也为NULL.由于map数组不是函数的本地数组,因此最好将其所有指针值设置为NULL,以便知道它何时包含有效指针以及何时不包含有效指针.

如果动态创建(使用new关键字)map [] []数组,则还需要使用delete关键字清理其内存.

希望这可以帮助.