关于C ++:在析构函数中删除指针

Deleting pointers in destructor

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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());

        }

    }

}

在程序结束时,调用析构函数以释放我分配的指针的内存,但是当到达"删除p_p_map [i];"时,该析构函数将被释放。 在析构函数中,XCode通知我未分配指针。 我是C ++的新手,但我觉得我已经为randomize()函数中的指针显式分配了内存。

我犯什么错误?


What error am I making?

一些:

首先,正如@uesp所指出的,您不匹配新呼叫并删除呼叫

其次,您正在使用"内存泄漏运算符":

1
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实例,则会发生以下情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)。


您必须将deletenew匹配,并且将delete[]new[]匹配。将一个与另一个混合会导致问题。因此,如果您这样做:

1
p_p_map = new Tile*[x];

您必须像这样删除它:

1
delete[] p_p_map;

和相同

1
delete[] p_p_map[i];

如果您创建类似:

1
pSomething = new Type;

然后您将其删除:

1
delete pSomething;