2012-08-25 67 views
0

鑑於這種一小段代碼:斷言這兩個指針指向NULL不發生後刪除()

#include <iostream> 
#include <assert.h> 
using namespace std; 


struct Foo 
{ 
    // something 
}; 


int main() 
{ 

    Foo *p1 = new Foo; 
    Foo * p2 = p1; 
    assert(NULL != p1); 
    delete p1; 
    p1 = NULL; 

    assert(NULL != p2); 
    delete p2; 

    cout << "everything is cool!" << endl; 

    return 0; 
} 

當我刪除p1,第二斷言(assert(NULL != p2);)沒有失敗,爲什麼?

輸出:everything is cool!

那麼爲什麼p2斷言不會失敗?

+1

因爲p2仍然設置爲p1所具有的地址。在更改之後,它不會獲得p1的值。 – drescherjm

回答

2
  1. 特別注意星星。

    int i; 
    
    int *p1 = &i; 
    assert(p1 != NULL); 
    
    int *p2 = p1; 
    assert(p2 != NULL); 
    
    *p1 = 10; 
    assert(i == 10); 
    assert(*p2 == 10); 
    
    p1 = NULL; // does not affect the object p1 was pointing at 
    
    assert(i == 10); 
    assert(*p2 == 10); 
    assert(p2 != NULL); // (which we already know, if the previous assert didn't crash) 
    
  2. 你是對的懷疑,一切都不是很酷。該程序在同一個對象上調用delete操作符兩次(「double free」錯誤),這往往會破壞堆。如果程序繼續,您會在某個時間點看到未定義的行爲。具有未定義的行爲相當於打破了編寫計算機程序的觀點。如果您想立即明確地看到類似這樣的錯誤,請在valgrind的memcheck或equivalent下運行。

4

當我刪除p1時,第二個斷言(assert(NULL!= p2);)不是 失敗,爲什麼?

刪除p1或分配給它的p2本身沒有影響。刪除p1後,p2仍指向該地址,即指向已停用的對象。它變成了一個所謂的懸掛指針。當然,訪問它或刪除它(你正在做的)是未定義的行爲。

+0

「非法」應該是「未定義的行爲」 – tenfour

+0

@tenfour我只是厭倦了「未定義的行爲」,認爲我會嘗試一些不同的行爲。 – cnicutar

0

delete p;不影響p。它破壞了p所指向的對象並釋放其內存。 p仍然有它以前的價值。

1

在C++中,最大和最容易混淆的詞之一是術語「刪除指針」。這無疑源於這樣一個事實:delete表達需要指針作爲它的參數:

T * p = new T; // #1 
delete p;  // #2 

然而,到底發生了什麼的是線#1創建一個新的,動態的,無名對象。再想一想:有沒有變量,其值是在#1行中創建的對象。這個東西實在遙不可及,因爲它確實不在任何範圍內。我們所有的是指針

要結束動態變量的生命週期,我們必須使用delete表達式。但既然我們已經知道,我們永遠只能真的有指針的對象,而不是對象本身*,表達CON ­ VENI ­耳鼻喉科­立法院接受指針到我們刪除的對象。

所以我們應該說,在第2行「我們通過給它指向delete表達式」(即&*p == p)來刪除對象*p

指針本身完全不受delete調用的影響。

*)是的,我們也可以有一個參考變量,像T & r = *new T;,但是這將是瘋狂的。