2012-01-31 64 views
5
# include <iostream> 

int main() 
{ 
using std::cout; 
int *p= new int; 

*p = 10; 
cout<<*p<<"\t"<<p<<"\n"; 
delete p; 
cout<<*p<<"\t"<<p<<"\n"; 

return 0; 

} 

輸出:
10 0x237c010
0 0x237c010'刪除指針'是否意味着'*指針= 0'?

刪除P,爲什麼指針p保留其值後這裏?不刪除釋放指針p?
「釋放指針」究竟意味着什麼?
是 '刪除P' 僅僅意味着 '* P = 0'?(從輸出似乎)

+0

那麼,它至少也會刪除指針所指向的數據,但我相信有人會很快得到更好的答案,說明「刪除」內存實際上意味着什麼。我懷疑它甚至可能不會記憶爲零,而只是允許再次分配空間。 – prelic 2012-01-31 01:36:51

+2

使用一點批判性思維 - 「* p = 0」如何適用於例如'的std :: string'? – ildjarn 2012-01-31 01:37:33

回答

6
刪除P,爲什麼指針p保留其值後

這裏?

這就是語言的設計。如果你想讓你持有的指針歸零,你需要自己指定爲零。指針p是另一塊內存,與它指向的分配/對象分開。

不刪除釋放指針p?

它調用析構函數的對象,並返回內存到系統(如免費)。如果它是一個數組(delete[]),則會調用所有元素的析構函數,然後返回內存。

'釋放指針'究竟意味着什麼?

當您想從系統中獲取一段內存時,請分配它(例如使用new)。當你完成使用它時,你可以使用相應的free/delete調用來返回它。這是一個資源,你必須返回。如果你不這樣做,你的程序將會泄漏(沒人願意)。

+0

@ Justin-請你解釋爲什麼指針p在上面的代碼中保留了它的值,即使在刪除之後呢? – 2012-01-31 01:37:24

+3

@Avinash:爲什麼要釋放內存改變其內容? – ildjarn 2012-01-31 01:37:58

+0

@AvinashSonawane擴展 – justin 2012-01-31 01:39:59

0

delete p只是在呼叫new運營商的過程中釋放分配的內存。它不會更改指針的值或釋放內存的內容。

+0

'delete'確保調用析構函數,它可以改變指針的值或釋放內存的內容。 – 2012-01-31 01:40:47

+0

@ Narrakan-如果指針值和指定值沒有變化,那麼釋放內存到底是什麼?由於指針值沒有改變,所以任何人都可以簡單地訪問那個'刪除'對象。 – 2012-01-31 01:42:04

+0

@AvinashSonawane很好,就像你自己看到的那樣,即使你刪除了它,你也可以訪問'* p',所以你仍然可以訪問那個內存,儘管它是未定義的行爲。 – 2012-01-31 01:43:26

1

刪除p後,爲什麼指針p保留其值?不刪除釋放指針p?

它釋放指針指向的內存(在調用任何適當的析構函數之後)。指針本身的值不變。

'釋放指針'究竟意味着什麼?

如上所述 - 這意味着釋放指針指向的內存。

是「刪除P」僅僅意味着「* P = 0」?(從輸出似乎)

號系統不寫什麼那是存儲釋放,如果它寫了一些它不必寫0。但是,系統通常必須以某種方式管理該內存,並且可能實際寫入指針所指向的內存區域。此外,可以將剛剛釋放的內存分配給其他內容(並且在多線程應用程序中,這可能會在delete操作甚至返回之前發生)。該內存塊的新所有者當然可以寫任何他們想要的內存。

指向釋放的內存塊的指針通常稱爲「懸掛」指針。解引用懸掛指針(讀取或寫入)是錯誤的。您有時會看到代碼立即在刪除指針後立即將指針NULL0指定給指針,有時使用刪除並清除指針的宏或函數模板。請注意,這不會修復懸掛指針的所有錯誤,因爲其他指針可能已被設置爲指向內存塊。

處理這些問題的現代方法是避免使用原始指針,而是傾向於使用智能指針,如shared_ptrunique_ptr

0

(請注意以下幾點是不是如何實際工作,以便把它當作一粒鹽。)

實施新的它裏面保存了所有可用內存的列表,當你說「詮釋* P =新的int;「它從可用內存列表中刪除一個int大小的塊並將其提供給您。當你運行「刪除p」時它會被放回到可用內存列表中。如果你的程序在沒有調用delete的情況下調用new 30次,你會從new得到30個不同的int大小的塊。如果你調用new,然後連續刪除30次,你可能(但不一定)得到相同的int大小的塊。這是因爲你說你在調用delete的時候沒有再使用它,所以new可以自由地重用它。

TLDR;刪除通知新的這部分內存是可用的,它不會觸及你的變量。

2

爲了理解什麼是釋放記憶的意思,你必須先了解什麼分配記憶的意思。接下來是一個簡單的解釋。

存在內存。內存是你可以訪問的一大塊東西。但是由於它是全球性的,你需要一些方法來分解它。管理誰可以訪問哪些內存的某種方式。管理內存分配的系統之一被稱爲「堆」。

堆擁有一定數量的內存(一些由堆棧擁有,一些由靜態數據擁有,但現在不知道)。在程序開始時,堆表示您無權訪問堆擁有的內存。

new int確實是兩倍。首先,它進入堆系統,並說:「我想要一塊適合存儲int的內存。」它返回一個指向這個的指針:堆中的一塊,你可以安全地存儲和檢索類型爲int的一個值。

你現在是一個int值得記憶的自豪的擁有者。堆保證,只要遵循其規則,無論你放在那裏,都會保留下來,直到你明確地改變它爲止。這是你和全能堆之間的約。

另一件事new int確實是用int值初始化該堆的那塊。在這種情況下,它是默認初始化的,因爲沒有值被傳遞(new int(5)將使用值5初始化它)。

從現在起,您可以合法地在這段內存中存儲一​​個int。您可以檢索存儲在那裏的int。而且你可以做另外一件事:告訴你堆完你的記憶。

當您撥打delete p時,會發生兩件事。首先,p被初始化。再次,因爲它是一個int,沒有任何反應。如果這是一個類,它的析構函數會被調用。

但之後,delete出來堆,並說,「嘿堆:記得這個指針,你給了我一個int?我現在完成了。」堆系統可以做任何想做的事情。也許它會清除內存,就像一些堆在調試構建中所做的一樣。但是,在發佈版本中,內存可能不會被清除。

當然,爲什麼堆可以做任何想做的事情是因爲,你刪除了那個指針,你就會和堆進入一個新的協議。之前,您要求爲int提供一塊內存,並且該堆有義務。你擁有這樣的記憶,並且堆可以保證只要你願意,它就是你的。你放在那裏的東西會留在那裏。

當你玩得很開心之後,你將它返回到了堆中。 。而這裏的合同來在當你說delete p,爲任何對象p,你說以下內容:

我莊嚴宣誓不會再碰這個內存地址!

現在,如果再次調用new int,堆可能會將該內存地址返回給您。它可能會給你一個不同的。但是在newdelete之間的時間內,您只能訪問由堆分配的內存。

鑑於此,這是什麼意思?

delete p; 
cout << *p << "\t" << p << "\n"; 

在C++的說法中,這被稱爲「未定義的行爲」。 C++規範有很多被聲明爲「未定義」的內容。當你觸發未定義的行爲任何事情都可能發生!*p可能爲0. *p可能是過去的值。做*p可能崩潰你的程序。

C++規範是你和你的編譯器/計算機之間的契約。它說明你可以做什麼,並說明系統如何響應。 「未定義的行爲」是當你在合同中,當你做了一些C++規範說你不應該做的事情時發生的事情。在那一刻,任何事情都可能發生。

當您撥打delete p時,您告訴系統您已使用p完成。通過再次使用它,你是說謊到系統。因此,系統不再需要遵守任何規則,例如存儲要存儲的值。或繼續運行。或者不從你的鼻子產生惡魔。管他呢。

你打破了規則。你必須承擔後果。

因此不,delete p不等於*p = 0。後者只是意味着「將0設置到p指向的內存中」。前者的意思是「我已經完成了使用p,指向的內存,我不會再使用它,直到你告訴我我可以」