delete p后,只是釋放了指針指向的內存空間。p並不會自動被置為NULL,而且指針還在,同時還指向了之前的地址
delete NULL編譯器不會報錯(因為delete空指針是合法的)
例:
對一個非空指針delete后,若沒有賦NULL,若再次delete的話,有可能出現問題。
如下代碼
int *p = new int(3);
delete p;
delete p;
用VC編譯運行將出現問題。
將其改為:
int *p = new int(3);
delete p;
p = NULL;
delete p;
則不會出現問題(因為delete空指針是合法的)。
轉自:http://blog.csdn.net/hudfang/article/details/43054243
具體的詳細原因看下面的例子:
《delete一個指針之后,要記得設置為NULL 》
眾所周知,最開始我們用new來創建一個指針,那么等我們用完它之后,一定要用delete將該指針刪掉。但是,值得注意的是,難道就僅僅是刪除這個指針這么簡單的么?下面,我們用一個程序來說明這個問題:
1 #include <iostream> 2 using namespace std; 3 int main() 4 { 5 int *p=new int; 6 *p=3; 7 cout<<"將3賦給p的地址后,指針p讀取的值:"<<*p<<endl; 8 delete p; 9 cout<<"刪除空間后,指針p讀取的值:"<<*p<<endl; 10 long *p1=new long; 11 *p1=100; 12 cout<<"創建新空間后,指針p中保存的地址:"<<p<<endl; 13 cout<<"指向新空間的指針p1保存的地址:"<<p1<<endl; 14 *p=23; 15 cout<<"將23賦給p的地址后,指針p讀取的值:"<<*p<<endl; 16 cout<<"將23賦給p的地址后,指針p1讀取的值:"<<*p1<<endl; 17 delete p1; 18 return 0; 19 }
在上面這個程序中,我們在第8行就將指針p利用delete刪掉了。但是,我們來看看程序的輸出結果:
對照着上面的程序,我們來分析一下這個輸出。首先,我們在程序的第5行初始化了一個指針p。之后輸出指針p讀取的值。由於第6行的原因,程序肯定會輸出3了。之后,我們在程序的第8行刪除了這個指針p。但是我們驚奇的發現,在程序的第9行竟然可以輸出指針p讀取的值。我們不是已經把它刪了么?其實不然,debug,上圖:
從監視窗口中,我們可以看見雖然程序的第8行已經將指針p刪除了,但是在監視窗口中p仍然存在,只是*p所指向的值不再是原來的3了,而是一個隨機數。這里就說明了一個非常重要的概念:我們在刪除一個指針之后,編譯器只會釋放該指針所指向的內存空間,而不會刪除這個指針本身。
然后我們接着往下分析。在程序的第10行我們又創建了一個long型的指針p1。在12行與13行的輸出中我們驚奇地發現,指針p保存的地址居然和指針p1保存的地址一模一樣!這個就說明了指針p和指針p1都指向內存的同一個地方!!!出現這種狀況的原因其實是由於編譯器。編譯器默認將釋放掉的內存空間回收然后分配給新開辟的空間。所以在第11行由於我們新開辟了一個可以保存long型變量的空間並且由p1來指向它,那么這里的p1指向的其實就是在程序第8行釋放掉的內存空間,即p指向的內存空間!所以,這就導致了兩個指針同時指向同一個內存空間。這是多不安全的一件事情啊!要知道,我們是把指針p刪了的啊!如果再重新對*p進行賦值操作,那么不是會連着*p1一起改動么?
果然,讓我們擔心的事情出現了。我們明明在程序的第11行中定義了*p1的值為100,但是在輸出上面,指針p1讀取的值竟然也是23。這個原因就是因為野指針p造成的。我們可以看到,在程序的第14行我們將23賦給了*p。又由於p和p1指向的是同一塊內存單元,所以在這里相當於也將p1所指向的內存單元中的值(原來是100),改成了23!這樣必然會導致程序的出錯!
那么我們就不禁要問了,對於這種由於野指針造成的問題,有沒有解決的方法呢?答案當然是有的了。我們只需要牢記下面這句話:
在刪除一個指針之后,一定將該指針設置成空指針(即在delete *p之后一定要加上: p=NULL)
我們來看一下在stdio.h中關於關鍵字NULL的定義:
/* Define NULL pointer value */ #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif
注意上面定義的第5行。這里其實就說明了NULL就是0。也就是說,我們在刪除完指針p之后,一定要把它變成空指針!只有這樣,才會杜絕上面程序中出現的野指針的錯誤。
p.s. 對於NULL的應用,我們不應該僅限於上面的方法,還可以應用NULL來判斷指針是否初始化成功了,如下例if中的判斷方法:
#include <iostream> using namespace std; int main() { int *p=new int; if (p==NULL) { //判斷指針p是不是空指針,如果是空指針,那么程序在這里就應該報錯 //報錯的方法有很多,比如說返回一個ERROR值: //return ERROR; } //判斷了操作成功之后我們才能進行一系列的操作 //... //用完指針p之后,一定要將其刪掉。這樣可以杜絕野指針的存在 delete p; //刪除指針p之后,一定要加上下面這句話,免得成為野指針 p=NULL; }
好了,下次一定要記住,在分配空間給指針之后,一定要用NULL來判斷一下是否成功了。然后在刪除這個指針的時候,也要用NULL來賦給指針,杜絕成為野指針!
O(∩_∩)O哈哈~寫完,收工~~~~
轉自:http://www.cnblogs.com/uniqueliu/archive/2011/07/18/2109778.html#
《對指針調用deletelater()后能立即將指針賦值為0嗎》
http://bbs.csdn.net/topics/390091038
比如我有一個對象A,含有一個指向某個對象(例如QUdpSocket)的指針,該對象A通過movetothread移動了一個次線程,然后在次線程中new了一個QUdpSocket對象,並把地址賦值給了對象A的那個指針,這樣QUdpSocket對象也是在次線程中了。
我的問題是,我需要在次線程析構前刪除掉對象A,因此需要給A寫一個析構函數。在函數體里對指向socket的指針調用deletalater(),這樣在回到次線程的時間循環后就能安全的刪除指針所指對象了。但是我能在調用完deleterlater后直接將
指針賦值為null嗎,也即:
if(m_udpsocket) { m_udpsocket->deletaLater(); m_udpsocket = 0; }
文檔中說deleterLater並不是立即被調用,而是把這個刪除時間加入到一個事件循環里了。所以,我想如果按照上面的代碼所寫,會不會出現這種情況:當刪除事件加入循環隊列后,指針被賦值為0,接着刪除事件被處理,這時因為指針為0,所以堆對象刪除失敗,造成了內存泄露?我自己在下面試了下,沒有碰見這種情況,但還是覺得不妥,不應該在后面對指針賦值為0.但是不這樣做的話,那這個指針豈不就成了一個野指針。在別的情況,我可能還想多次重復利用這個指針,那這樣不就用不了了嗎?
答:當然可以,deleteLater並不依賴於這個指針的值,只能使用直接調用函數的方式,
不能使用connect(p***, SIGNAL(disconnected()), p***, SLOT(deleteLater()));
connect(p***, SIGNAL(disconnected()), this, SLOT(sltClose()));
void sltClose()
{
p***=NULL;//槽函數調用沒有固定順序
}
看http://www.cnblogs.com/liushui-sky/p/5851936.html中
注:我理解調用deletelater (如指針QTcpSocket *p調用 p->deletelater();)之后已經把當前的QTcpSocket 對象的內存地址通過this賦值給消息隊列了,所以把外部的指針p置為NULL不影響最終對象的delete。
記住:p存放的是指向QTcpSocket對象的內存地址,而p本身只是一個指針地址。
參考:http://blog.csdn.net/zzwdkxx/article/details/50748908