delete p后,只是釋放了指針中存放的地址中的內存空間。但是指針變量p仍然存在(即指針p本身所占有的內存),且p中存放的地址還是原來的地址。
例如:
對一個非空指針delete后,若沒有將p賦為NULL,若再次delete的話,會出現問題。
如下代碼:
#include <iostream> int main() { int* p = new int(3); delete p; delete p; return 0; }
在ubuntu14.04中使用g++進行編譯無問題,但運行時報錯如下:
意思就是對同一指針變量進行了兩次釋放內存的操作,這是不合法的。
因為第一次釋放后,指針p指向的那塊區域已經變為不可訪問區域了,再執行一次delete p,試圖對一塊不可訪問的區域進行釋放,這是不合法的。
將其改為:
#include <iostream> int main() { int* p = new int(3); delete p; p = NULL; delete p; return 0; }
則編譯和運行都沒有問題,因為C++保證delete值為NULL的指針是安全的。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
具體的說明如下:
還是先看代碼:
1 /* 2 *Compile Environment:linux ubuntu14.04.5 g++ 3 *Author: mengjia 4 *Date:20180520 5 **/ 6 #include <iostream> 7 using namespace std; 8 int main() 9 { 10 int *p = new int; 11 *p = 3; 12 cout << "將3賦給p的地址后,指針p讀取的值:" << *p << endl; 13 cout << "刪除空間前,指針p中存放的地址:" << p <<endl; 14 delete p; 15 cout<<"刪除空間后,指針p存放的地址:"<< p <<endl; //在vs2017中,p中存放的地址會改變,但在g++中不會,應該是vs2017中對其進行優化了,讓p指向了一個不可訪問的地址,避免delete之后又誤操作了p 16 cout << "刪除空間后,指針p讀取的值:" << *p << endl; //在vs2017中,對×p的訪問直接會報錯(引發了異常: 讀取訪問權限沖突),但在g++中,可 17 以正常往下執行。 18 long *p1 = new long; 19 *p1 = 100; 20 cout << "創建新空間后,指針p中存放的地址:" << p << endl; 21 cout << "指向新空間的指針p1存放的地址:" << p1 << endl; 22 *p = 23; 23 cout << "將23賦給p的地址后,指針p讀取的值:" << *p << endl; 24 cout << "將23賦給p的地址后,指針p1讀取的值:" << *p1 << endl; 25 delete p1; 26 // system("pause"); 27 return 0; 28 }
輸出結果為:
從第13和第15行中可以看到,delete指針p前后,p中存放中地址並未改變。這就說明一個非常重要的結論:
delete一個指針后,編譯器只是釋放了指針中存放的地址中的內存空間,但p中存放的地址還是原來的地址。
在程序的第18行,創建了一個long型的指針p1,在20和21行的輸出中發現,指針p保存的地址居然和指針p1保存的地址一毛一樣。說明指針p和指針p1都指向內存的同一個地方。出現這種狀態是因為編譯器默認將釋放掉的內存空間回收然后分配給新開辟的空間。所以18行,當開辟一個可以保存long型變量的空間並且由p1來指向它時,分配的空間為p指向的內存空間。
如此,將導致兩個指針同時指向同一內存空間。這在C++中是非常忌諱的。
如上,在程序中定義了*p1 = 100;而后再操作p,使*p = 23;而后讀取p1指向的內存中的值,變為了23。這就會使得已經delete的指針,若操作不當,會影響到程序的其它指針。這種情況就是由於野指針p造成的。
要避免這種情況的發生,解決辦法就是:
在刪除一個指針之后,一定要將該指針設置成空指針,即在delete p之后,要加上: p = NULL
補充說明:
請注意程序中第15行和16行的注釋,這段程序在vs2017上是編譯不通過的。原因就如注釋所言,vs2017對其進行了優化,delete之后,讓p的指向改變了,改變為指向一個不可訪問的地址,使得之后如果有任何*p相關的操作,都會直接報錯。其目的,我覺得就是保證在源頭斷絕,不讓出現野指針的情況。
但這種依賴於編譯器的優化,對我們理解C++並沒有好處。