關於C++ delete 來釋放new分配的記憶體

gaopengtttt發表於2016-04-27
一般在C語言中我們使用malloc和free進行記憶體分配和釋放,但是在C++中增加了一個新的
new和delete 操作來進行,按照C++的說法delete是釋放記憶體但是指標得到保留,防止記憶體
洩露,並且NEW和DELETE要成對出現。我們知道指標本生也是一個儲存在記憶體中某個位置的變數,
如果釋放了記憶體我們是否可以考慮為其中的值得到了刪除,而指標自身可以再次指向其他的值?
而還有一點我們需要明白使用NEW分配的記憶體是HEAP而變數的賦值是棧,


在OS中我們大概可以理解如下(32位系統為例),我這裡的共享是指執行緒是否共享:


4G
     kernel --核心記憶體
3G   text --程式碼文字 共享
     data --初始化的全域性變數和靜態變數 共享
     dss  --未始化的全域性變數和靜態變數 共享
     棧   --級動態變數陣列等 不共享
     堆   --malloc 共享
0    共享庫 --庫檔案 mmap 對映 共享


可以看到棧和堆不是一個區域,並且棧始終是自我釋放的遵循後入先出原則


我們接下來用如下的小程式帶上GDB進行除錯


  8 #include
  9 using namespace std;
 10 
 11 
 12 int main(void)
 13 {
 14     int *p;  //一個不初始化的指標,不能使用*p=一個INT數字,只能賦予一個指標變數p=(init *)0x130000表示p指標指向130000位置
 15     short *b  = new short;
 16     short *c = new short;
 17 
 18     *b=0X128;
 19 
 20     cout<<"noinit int address is :"<< p <<" "<<sizeof(*p)<<endl;
 21     cout<<"short b address is :"<< b <<" "<<sizeof(*b)<<"\n";
 22     cout<<"short c address is :"<< c <<" "<<sizeof(*c)<<endl;
 23     delete b; //成對出現
 24     delete c;
 25     //DELETE不釋放指標只是釋放記憶體,那麼指標指向的記憶體可以用於其他用途
 26     cout<<"init int address is :"<< b <<" "<<sizeof(*b)<<"\n";
 27     cout<<"noinit dou address is :"<< c <<" "<<sizeof(*c)<<endl;
 28 
 29     *b=0X256; //直接賦予值,賦值成功
 31     delete b; //不成對出現
 32     *b=0X512; //便於觀察而已
 33     delete b; //便於觀察,避免指標釋放  
  }
~ 如果我們在
 23     delete b;      
 後去GDB *b的只為0那麼說明delete起到了效果             
 gdb ./a.out 
(gdb) b 23
Breakpoint 1 at 0x400a79: file pointer2.cpp, line 23.
(gdb) r


Breakpoint 1, main () at pointer2.cpp:23
23              delete b;
(gdb) p b
$1 = (short *) 0x602010
(gdb) x/2xh 0x602010 
0x602010:       0x0128  0x0000
可以看到當前為0X0128資料在這個儲存2個位元組裡面我是也就是0x602010 0x602011
(gdb) n
24          delete c;
(gdb) x/2xh 0x602010
0x602010:       0x0000  0x0000
這裡跑完了delete b;  可以看到資料沒有了在記憶體中,繼續
繼續向下


29              *b=0X256;
(gdb) n
30          delete b;
(gdb) p b
$3 = (short *) 0x602010
這裡跑完了 *b=0X256;但是指標位置沒有變化,也就是DELETE後指標得到了保留
繼續
(gdb) p *b
$4 = 598
(gdb) x/2xh 0x602010
0x602010:       0x0256  0x0000


可以看到資料沒有問題。繼續看看是否能DELETE
(gdb) n
(gdb) x/2xh 0x602010
0x602010:       0x2020  0x0060
可以看到delete並沒有刪除資料而已弄了一些垃圾資料進來。
其實這個程式直接跑會報錯
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000000f1f010 ***
Aborted (core dumped)
用GDB只是為了找到原因


所以我們必須new和delete 成對使用,否者結果是不確定的,對空指標delete是安全的
delete後指標是得到了保留的沒有問題,如果是動態陣列將不能使用sizeof來確定他的長度
指標我感覺是使用的棧,同時在函式結束時自我釋放。


附帶關於GDB的記憶體檢視
轉自:http://www.cnblogs.com/super119/archive/2011/03/26/1996125.html


格式: x /nfu


說明
x 是 examine 的縮寫


n表示要顯示的記憶體單元的個數


f表示顯示方式, 可取如下值
x 按十六進位制格式顯示變數。
d 按十進位制格式顯示變數。
u 按十進位制格式顯示無符號整型。
o 按八進位制格式顯示變數。
t 按二進位制格式顯示變數。
a 按十六進位制格式顯示變數。
i 指令地址格式
c 按字元格式顯示變數。
f 按浮點數格式顯示變數。


u表示一個地址單元的長度
b表示單位元組,
h表示雙位元組,
w表示四位元組,
g表示八位元組




Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char) and s(string).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes)


舉例
x/3xh buf
表示從記憶體地址buf讀取內容,
h表示以雙位元組為一個單位,
3表示三個單位,
x表示按十六進位制顯示


</sizeof(*c)<<endl;
</sizeof(*b)<<"\n";
</sizeof(*c)<<endl;
</sizeof(*b)<<"\n";
</sizeof(*p)<<endl;

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2089546/,如需轉載,請註明出處,否則將追究法律責任。

相關文章