我有一些指针,我在类的构造函数中分配,然后尝试在其析构函数中删除:
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());
}
}
}
在程序结束时,调用析构函数来释放我分配的指针的内存,但是当它到达&#34;删除p_p_map [i];&#34;在析构函数中,XCode通知我指针未分配。我是C ++的新手,但我觉得我非常明确地为randomize()函数中的指针分配了内存。
我犯了什么错误?
答案 0 :(得分:1)
您必须将delete
与new
和delete[]
与new[]
匹配。将一个与另一个混合会导致问题。所以如果你这样做:
p_p_map = new Tile*[x];
你必须删除它:
delete[] p_p_map;
与
相同delete[] p_p_map[i];
如果您创建类似:
pSomething = new Type;
然后你删除它:
delete pSomething;
答案 1 :(得分:1)
我犯了什么错误?
一些:
首先,正如@uesp指出的那样,你不匹配新的和删除调用
其次,您正在使用&#34;内存泄漏运算符&#34;:
p_p_map[i][j] = *new Tile(Tile::TileSize * i, Tile::TileSize * j, TileType::randomType());
构造new Tile(...)
分配内存。然后,取消引用该存储器(未存储在任何地方),并将结果分配给p_p_map [i] [j]。
因为指针没有存储在任何地方,所以它被泄露了。
第三,你不尊重RAII。虽然这在技术上本身并不是一个错误,但是编写代码的方式是不安全的,而在内存不足的情况下,你会获得UB。
例如,如果构建一个x和y值较大的Tile
实例会发生什么:
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
实例是&#34;半结构&#34; (即处于无效状态)并且不会调用析构函数。
在这种情况下,所分配的类的所有内容都会泄露,并且(特别是如果你分配了一个大的)你的应用程序将处于低内存条件下。
要解决此问题,请确保每个指针都由一个不同的类实例(RAII的一部分)管理。这确保了如果分配失败,则在退出作用域之前释放分配的资源,作为堆栈展开的一部分(如@CaptainObvlious所说,对数组使用std :: vector,对每个元素使用std :: unique_ptr)。