2012-03-18 77 views
3

可能重複的:
C++ delete - It deletes my objects but I can still access the data?行爲刪除[]

我很好奇爲什麼我收到以下的(虛構的)代碼以下行爲。我使用在Ubuntu 10.10

#include <iostream> 

int main(int argc, char *argv[]) 
{ 
    int N = 5; 
    int *myarr = new int[N];//create an integer array of size 5 

    for (int i = 0; i < N; ++i) 
    { 
     myarr[i] = 45; 
     std::cout << myarr[i] << std::endl; 
    } 


    delete[] myarr;//kill the memory allocated by new 
    std::cout << "Let's see if the array was deleted and if we get a segfault \n" ; 

    for (int i = 0; i < N; ++i) 
    { 
     std::cout << myarr[i] << std::endl; 
    } 


    return 0; 
} 

代碼編譯,甚至與-Wall標誌 GCC 4.4.5。輸出是

Desktop: ./a.out 
45 
45 
45 
45 
45 
Let's see if the array was deleted and if we get a segfault 
0 
0 
45 
45 
45 
Desktop: 

怎麼會在myarr陣列仍然可以就好像它是一個不段錯誤被徹底刪除訪問? 而且即使myarr數組被刪除怎麼來的價值45似乎仍然在位置2,3正確打印和4

總之什麼是真正在這裏做delete[]

回答

3

delete[]調用數組中每個元素的析構函數,並告訴您的計算機不再使用該內存。記憶仍然存在,你只是不被允許使用它。

你看到的是未定義的行爲。它可能會以各種方式失敗,但是因爲你的程序太短,它可能會像你大部分時間看到的那樣工作。

1

運營商delete[]只釋放內存。在delete[]未定義行爲後訪問內存。

myarr指向的內存可能仍會包含您分配一段時間的值。該內存地址將包含相同的值,直到有人向其寫入內容爲止。

2

釋放內存確實不是保證如果您以後嘗試訪問該內存,將會收到段錯誤。基本上,在釋放內存後訪問內存會導致未定義的行爲 - 任何事情都可能發生。

就你而言,delete[]運算符釋放內存並將其返回到運行時庫。但是,運行時庫掛在內存上,不會立即將其返回到操作系統(畢竟,您可能會很快再次需要它)。運行時庫將使用應用程序已釋放的內存管理其自己的數據結構。例如,您看到的零可能是空閒列表結構的一部分。

1

內存被釋放,其中的一部分被擦除,你可以看到。它仍然可以被訪問,但是你的程序沒有崩潰的事實主要是由於沒有足夠的時間爲這個內存分配給不同的對象,或者你沒有試圖做任何調皮的事情,像使用它內部的值作爲緩衝區的偏移量或其他東西。

0

您認爲delete[]的功能是什麼?它調用數組中所有對象的析構函數,然後釋放它。您的myarr指針現在指向釋放的內存,並且是無效的指針。

顯然,內存還沒有被重用,所以它仍然恰好包含你釋放之前存在的數據,但這是未定義的行爲這意味着你不能依賴它。如果你這樣做,你會有一天有各種令人興奮的難以發現的錯誤。

0

delete []調用析構函數,然後告訴系統先前分配的內存不會有任何進一步的用法,但指針仍然指向開始地址。

#include <iostream> 

int main(int argc, char *argv[]) 
{ 
    int N = 5; 
    int *myarr = new int[N];//create an integer array of size 5 

    for (int i = 0; i < N; ++i) 
    { 
     myarr[i] = 45; 
     std::cout << myarr[i] << std::endl; 
    } 


    delete[] myarr;//kill the memory allocated by new 
    std::cout << "Let's see if the array was deleted and if we get a segfault \n" ; 

    int *dumb = new int[N]; 

    dumb[3]=0; 

    for (int i = 0; i < N; ++i) 
    { 
     std::cout << myarr[i] << std::endl; 
    } 


    return 0; 
} 

,輸出是:

45 
45 
45 
45 
45 
Let's see if the array was deleted and if we get a segfault 
0 
45 
45 
0 
45 

因爲內存過小,可能還沒有被其他的進程保留你沒有得到分割故障。但試試這個:

#include <iostream> 

int main(int argc, char *argv[]) 
{ 
    int N = 50000; 
    int *myarr = new int[N];//create an integer array of size 5 

    for (int i = 0; i < N; ++i) 
    { 
     myarr[i] = 45; 
     std::cout << myarr[i] << std::endl; 
    } 


    delete[] myarr;//kill the memory allocated by new 
    std::cout << "Let's see if the array was deleted and if we get a segfault \n" ; 
    std::cin >> N; 
    int *dumb = new int[N]; 

    dumb[3]=0; 

    for (int i = 0; i < N; ++i) 
    { 
     std::cout << myarr[i] << std::endl; 
    } 


    return 0; 
} 

並輸入一些數字,例如, 9000

0

所有已經寫在這裏的都是真的,我只想在上多說一點,爲什麼你所做的是未定義的行爲。

  1. 在進程的內存分配方面,操作系統不是零售商,你不能讓說10個字節,你只能要求在頁面內存(通常爲1頁= 4KiB)。
  2. 但是進程在較小的塊上運行,這就是爲什麼每個進程都有自己的「分配器」 - 這是實施運營商刪除。這兩個野獸坐在你的程序和操作系統之間。他們要求內存在頁(例如請給我3頁的內存),並管理您的程序(進程)這些網頁。
  3. 當你想分配比如說10個字節,運營商將分配(至少)一個頁面(如果需要),並給你一個指向該頁面上的內存的指針,它也會記得從該地址(它給了你)使用了10個字節。
  4. 當你不再需要這10個字節時,你可以調用運算符刪除 - 這個野獸會記下10個字節(在上面提到的頁面上)不再使用。 如果整個頁面不再使用可以(但不必)被釋放(回到系統)。如果您嘗試訪問釋放的內存時會發生這種情況 - 它會給您分段錯誤(頁面不再由您的進程擁有),但是如果頁面沒有返回給系統,它仍然可用,(但你不知道這是肯定
  5. 即使存儲仍然可以訪問你不應該訪問它,因爲:
    • 內容可能爲其他分配,這意味着它可以改變重複使用
    • 的內容可以(並經常)使用內部結構刪除。如果寫入已刪除的內存,則可能會導致這些結構的損壞,這通常會導致段錯誤發生在完全意想不到的地方(例如,在代碼中某些其他完全無關的地方執行delete []時)。

請記住,所有我上面寫的僅僅是非常簡化的版本,這是很複雜的,然後,但我希望它會給你一些想法是怎麼工作的「引擎蓋下」。 阿門。