2013-01-19 84 views
5

我在看下面的一段鏈表代碼,我在網上找到:C++ - 爲什麼刪除後將對象設置爲空?

void DeleteAfter(Node **head){ 
     if(*head==NULL){ 
      return; 
     }else{ 
      Node *temp = NULL; 
      temp = (*head)->next; 
      (*head)->next = (*head)->next->next; 
      delete temp; 
      temp=NULL; 
     } 
} 

我不是熟練使用C++,所以這可能是一個壞的問題,但爲什麼是臨時被之後被設置爲NULL刪除嗎?這是一個必要的步驟嗎?

+1

不要。只需使用智能指針。 – chris

+3

這裏是否將它設置爲NULL是絕對不相關的。 'temp'是一個具有自動存儲的變量,意味着退出'else'模塊後它將超出範圍。但正如@chris所說,只是使用智能指針 –

+2

,'* head'不是'NULL'的事實並不意味着'(* head) - > next'不是'NULL',並且您試圖解引用那個指針('(* head) - > next - > ...') –

回答

7

這是沒有必要的。即使沒有結果,有些人養成這樣做的習慣。一個積極的編譯器優化器將消除這個代碼,所以它實際上並沒有造成任何傷害。不過,我會寫:

void DeleteAfter(Node *head) { 
    if (head) { 
    Node *next = head->next; 
    if (next) { 
     head->next = next->next; 
     delete next; 
    } 
    } 
} 

注意我消除了一個間接無用的水平,增加了一個檢查,以確保有一個「節點之後,」刪除。

該習慣的基本原理是,如果一個指針總是引用一個有效的對象或爲null,那麼可以將空檢查視爲等效於有效性檢查。

由於這個原因,Ada是安全關鍵系統中經常使用的語言,它將指針初始化爲null並定義它的delete等效運算符,以自動將其參數設置爲null。你的C++正在模擬這種行爲。

在實踐中,這門學科的價值不是你所希望的。一旦很長一段時間,它可以防止一個愚蠢的錯誤。然而,一件好事是調試器顯示指針內容是有意義的。

+0

請記住,head-> next可能是NULL,導致此代碼在head-> next = head-> next-> next; – drescherjm

+0

如此真實......我更新了這個解釋。檢查頭節點而不是head-> next是沒有意義的。 – Gene

0

這不是必要的,有些人(包括我)認爲這是不好的做法。

將其設置爲NULL的動機是您可以隨後檢查它是否被刪除,如果不是,則可以訪問它。此外,這將防止雙重刪除,因爲delete上的NULL指針是無操作的。

另一方面,它可以隱藏錯誤。如果該對象被刪除,使用它沒有意義,對吧?你應該知道該對象被刪除,不依靠檢查。

例如

if (p != NULL) //or just if (p) 
    p->doStuff() 

爲什麼?你不知道它是否被刪除?不是清理邏輯的一部分?

1

在刪除它之後,您不必將局部指針變量設置爲NULL。如果要在NULL檢查後重新使用指針,您應該將指針設置爲NULL,您可以安全地爲其分配新地址。通常我們會它用於指針成員變量和全局指針變量。

1

如果temp是一個全局或成員變量,那麼設置爲NULL並不是一個壞主意。

我習慣於在C代碼中使用保守的垃圾回收器後將指針設置爲NULL。沒有指向未使用內存的指針是它如何發現垃圾收集。但在這種情況下,你也應該做

temp->next = NULL; 
1

如果變量temp可能被再次在代碼中使用以後,那麼它是很好的做法,將其設置爲NULL。

有兩個原因,通常在釋放指針後將其設置爲NULL。

1.)一旦你釋放一個指針,指向的地址的內存不再可用於你的程序。從理論上講,該內存現在可以被任何其他程序使用,包括操作系統本身!試圖釋放已經發布的指針,並指出誰知道可能導致嚴重問題的指針。幸運的是,現代操作系統可以防止這種情況發生,但程序仍然會因非法訪問錯誤而崩潰。釋放一個空指針OTOH將完全不做任何事情。

2.)在使用*運算符取消引用它之前,您應該始終檢查指針是否爲NULL。取消引用NULL指針將導致運行時錯誤。取消引用指向某些任意內存的已釋放指針甚至更糟糕。釋放的指針應始終設置爲NULL,以便後面的代碼可以假定非空指針指向有效數據。否則,無法知道指針是否仍然有效。

至於原來的問題,指針變量temp被聲明爲一個短函數中的局部變量,它不再被使用。在這種情況下,只要函數返回,就不需要將其設置爲NULL。

然而,行...

(*head)->next = (*head)->next->next; 

未能確保(*head)->next不爲空試圖取消引用之前,一個沒有沒有。

一個更好的版本是...

int DeleteAfter(Node **head){ 
    Node *node_after = NULL; 

    if(*head==NULL) 
    return -1; 

    node_after = (*head)->next; 

    if(node_after == NULL) 
    return -1; 

    (*head)->next = node_after->next; 
    delete node_after; 

    return 0; 
    } 

現在使用功能可以檢查節點的缺失是否是返回值成功並沒有試圖刪除一個不存在風險的人節點。

0

在你的代碼示例中沒有明顯的直接好處,但是可以說是一個孤獨的維護成本優勢。這個想法是,有人可能最終添加代碼後刪除臨時試圖解引用溫度。這可能會發生,只是不注意刪除,或者通過移動先前刪除後訪問臨時文件的行。

下面是一個例子:

int * i = new int(12); 
std::cout << *i << std::endl; // output is 12. 
delete i; 
// i = 0; // This would cause the program to fail on the next line. 
std::cout << *i << std::endl; // output is random for me. 

請注意,這不能掩蓋缺陷,實際上不設置指針爲空會,在這種情況下,隱藏該缺陷爲*我返回一個隨機值。

大多數人會說,編譯器可能會優化i = 0,無論如何,對指針的賦值大多是無害的。對我而言,在專業開發時,我總是犯錯。

相關問題