在析构函数

问题描述:

删除指针我有一些球,我在类的构造函数分配,然后尝试在它的析构函数删除:在析构函数

TileMap::TileMap(int x, int y) { 

    mapSize.x = x; 
    mapSize.y = y; 

    p_p_map = new Tile*[x]; 

    for(int i = 0; i < x; i++) { 

     p_p_map[i] = new Tile[y]; 

    } 

    randomize(); 

} 

TileMap::~TileMap() { 

    for(int i = 0; i < mapSize.x; i++) { 

     delete p_p_map[i]; 

    } 

    delete p_p_map; 

} 

void TileMap::randomize() { 

    for(int i = 0; i < mapSize.x; i++) { 

     for(int j = 0; j < mapSize.y; j++) { 

      p_p_map[i][j] = *new Tile(Tile::TileSize * i, Tile::TileSize * j, TileType::randomType()); 

     } 

    } 

} 

在程序结束时调用析构函数释放内存我分配的指针,但是当它到达“delete p_p_map [i];”时在析构函数中,XCode通知我该指针未被分配。我是C++的新手,但我觉得我很明确地将内存分配给了randomize()函数中的指针。

我犯了什么错误?

+2

使用'std :: vector'和'std :: unique_ptr'''' boost :: unique_ptr'或'std :: shared_ptr'''' boost :: shared_ptr',您将获益良多,而不是管理内存你自己。 – 2014-11-03 14:39:53

+0

这听起来像你没有遵循[Rule of Three](http://stackoverflow.com/questions/4172722),如果你坚持通过虐待原始指针来管理动态对象,这很容易中断。使用'std :: vector'。 – 2014-11-03 14:46:45

您必须匹配deletenewdelete[]new[]。混合一个与另一个导致问题。所以,如果你这样做:

p_p_map = new Tile*[x]; 

你要删除它喜欢:

delete[] p_p_map; 

,并同与

delete[] p_p_map[i]; 

如果你创造的东西,如:

pSomething = new Type; 

然后你删除它像:

delete pSomething; 
+1

另外OP的示例在'randomize()'函数中产生泄漏。 – 2014-11-03 14:40:07

+2

确实,'* new'几乎总是内存泄漏的标志,通常应该被彻底省略。这里也;只使用'... = Tile(i,j,type)' – MSalters 2014-11-03 14:47:39

我犯了什么错误?

几个:

首先,@uesp指出的那样,你错配了new和delete

其次,您使用的是 “内存泄露经营者”:

p_p_map[i][j] = *new Tile(Tile::TileSize * i, Tile::TileSize * j, TileType::randomType()); 

构造new Tile(...)分配内存。然后,该内存(不存储在任何地方)被解除引用,并且结果被分配给p_p_map [i] [j]。

因为指针没有存储在任何地方,所以泄漏了。

第三,你不尊重RAII。虽然这在技术上本身不是一个错误,但您编写代码的方式不安全,而且在内存不足的情况下,您将获得UB。

例如,这里是如果你构建一个Tile实例与x和y的较大值会发生什么:

TileMap::TileMap(int x, int y) { // e.g. (x = 1024 * 1024, y = 1024 * 1024 * 1024) 

    mapSize.x = x; 
    mapSize.y = y; 

    p_p_map = new Tile*[x]; // allocate 1049600 pointers block 

    for(int i = 0; i < x; i++) { 

     p_p_map[i] = new Tile[y]; // run out of memory (for example) half way through the loop 

    } 

    randomize(); 
} 

根据您的分配失败,构造函数不会完成执行,这意味着你的TileMap实例“半建“(即处于无效状态),析构函数不会被调用。

在这种情况下,所有分配的类都被泄漏,并且(特别是如果分配了较大的大小),应用程序将保留在低内存条件下。

要解决这个问题,请确保每个指针都由一个类的不同实例(RAII的一部分)管理。这确保了如果分配失败,分配的资源将在释放范围之前释放,作为堆栈展开的一部分(如@CaptainObvlious所述,对数组使用std :: vector,对每个元素使用std :: unique_ptr)。