2014-11-03 105 views
0

刪除指針我有一些球,我在類的構造函數分配,然後嘗試在它的析構函數刪除:在析構函數

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

回答

1

您必須匹配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

1

我犯了什麼錯誤?

幾個:

首先,@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)。