在析构函数
删除指针我有一些球,我在类的构造函数分配,然后尝试在它的析构函数删除:在析构函数
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()函数中的指针。
我犯了什么错误?
您必须匹配delete
与new
和delete[]
与new[]
。混合一个与另一个导致问题。所以,如果你这样做:
p_p_map = new Tile*[x];
你要删除它喜欢:
delete[] p_p_map;
,并同与
delete[] p_p_map[i];
如果你创造的东西,如:
pSomething = new Type;
然后你删除它像:
delete pSomething;
另外OP的示例在'randomize()'函数中产生泄漏。 – 2014-11-03 14:40:07
确实,'* 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)。
使用'std :: vector'和'std :: unique_ptr'''' boost :: unique_ptr'或'std :: shared_ptr'''' boost :: shared_ptr',您将获益良多,而不是管理内存你自己。 – 2014-11-03 14:39:53
这听起来像你没有遵循[Rule of Three](http://stackoverflow.com/questions/4172722),如果你坚持通过虐待原始指针来管理动态对象,这很容易中断。使用'std :: vector'。 – 2014-11-03 14:46:45