2013-02-13 42 views
0

我有一段代碼正在創建一個基於圖塊的級別。爲什麼不訪問已刪除的對象導致我的程序崩潰?

class Level { 

//Variables 
//=================================================== 
public: 
    Tile *** TileGrid; //A 2d array of pointers to tiles 
    int TilesWide, TilesTall; 

//Methods 
//=================================================== 
public: 
    Level::Level(char * fileName); 
    Level::~Level(); 
    void Draw(); 
}; 

我爲TileGrid分配內存,一切都很好。我也爲這個班級設置了一個析構函數。

Level::~Level() { 

    for (int i = 0; i < TilesTall; i++) { 
     for (int j = 0; j < TilesWide; j++) 
      //delete the looped tile being pointed to 
      delete TileGrid[i][j]; 

     //delete the row 
     delete [] TileGrid[i]; 
    } 

    //delete the array of rows 
    delete [] TileGrid; 
} 

對於咯咯我決定我會刪除我的Level實例。在我這樣做後,我發現我仍然可以調用它的Draw方法。

在調試器中,TilesWide和TilesTall的值是一個巨大的負數,所以我的for循環迭代網格時沒有繪製任何值。

試圖訪問一個刪除的變量不會導致某種崩潰?

+1

@LuchianGrigore:不,這個問題是不同的。這個問題是關於返回一個局部變量的地址;這是關於在堆上使用後免費的。 – 2013-02-13 20:20:58

回答

1

你所做的是被稱爲「未定義的行爲」。

未定義的行爲並不意味着「會崩潰」,這意味着任何事情都可能發生。該程序可以格式化您的硬盤,它可以播放巴赫奏鳴曲,它可以在屏幕上繪製一張達菲鴨的圖片,它可以給你一個負值,並且在任何情況下它都會是你要求的正好

不包括崩潰,崩潰。

現在讓我們假設一個合理的C++實現。方法Level::Draw不會隨您傳遞它的哪個實例Level而變化,所以您調用的函數不依賴於實例。該實例作爲參數傳遞給此函數,作爲指向堆中某些內存的指針,該內存曾經是變量的副本。從那時起,它已被用於其他目的的回收,或者可能包含有關堆的簿記信息 - 什麼是未定義的。 (並且,如果運行時返回頁面到系統,訪問它可能會出現段錯誤)

然後,您繼續將該垃圾解釋爲某些值。事情是非常好的,因爲隨機垃圾看起來像一個C++ int埃格爾(在這種情況下,作爲一個負整數)幾乎總是在大多數系統上。現在,一旦開始解引用指針(並訪問內存的「隨機」部分)或寫入狀態this,崩潰很可能會發生(如果不是那麼,那麼以後或其他地方)。

2

它不會必然導致崩潰。它可能會,但可能不會。它會導致所謂未定義行爲

未定義行爲
爲這本國際標準中並沒有規定要求

它可能只是儘可能多的崩潰爲毀滅宇宙的行爲。

2

可能導致崩潰。它取決於內存是否被另一個對象覆蓋和/或內存系統是否將該頁面重新分配給另一個進程(或從當前進程中取消分配頁面)。底線是,你不能依靠它的工作(如你所知)

+0

這個答案假設存在標準不知道的「過程」和「頁面」。 (並且在真實系統中,對象本身不可能有整個頁面) – 2013-02-13 20:19:45

+1

是的。我沒有考慮這個標準,但實際上從操作系統和CPU的角度來看可能會發生什麼。我並不是建議對象本身有一個頁面,但是頁面(取決於操作系統)可能會返回,如果它沒有被進程使用 – 2013-02-13 20:20:47

1

刪除後訪問對象是未定義的行爲。未定義的行爲可能意味着任何事情,從「出現成功」到「崩潰」到「格式化硬盤」。

相關問題