2012-12-06 117 views
1
void removeDuplicateWithHashtable(LinkedListElement<char> *head) 
{ 
    LinkedListElement<char> *runner = head; 
    LinkedListElement<char> *previous = nullptr; 
    hash_map<char, bool> record; 
    while (runner) { 
     if (record.count(runner->Data) == 0) { 
      pair<char, bool> item(runner->Data,true); 
      record.insert(item); 
     }else 
     { 
      free(runner); 
      previous->Next = runner->Next; 
     } 
     previous=runner; 
     runner=runner->Next; 
    } 
} 

最初我以爲會出現錯誤。因爲在free(runner),如果我釋放內存,我不能訪問亞軍 - >下一步。 但GCC編譯器運行成功。爲什麼這個函數不會導致錯誤?

其實如果我改變自由刪除亞軍,它也是正確的。 我可以問問原因可能是空閒或刪除只是告訴你內存是否可用實際上沒有清除數據裏面,所以你也可以訪問Next。 我可以問一下如何改善它嗎?

回答

3

這不是一個編譯錯誤,但問題(未定義行爲)將在運行時顯現。如果您選擇在未分配的內存上調用free,編譯器不會阻止您。

+0

其實如果我改變自由刪除亞軍,這也是正確的。 我可以問問原因可能是空閒或刪除只是告訴你內存是否可用實際上沒有清除數據裏面,所以你也可以訪問Next。 我可以問一下如何改善它嗎? – Hypnoz

+0

@Hypnoz它不是'delete'或'free'的問題 - 它不會是編譯器錯誤。簡單的事實是你不應該試圖釋放未分配的內存。 – mathematician1975

3

這樣的邏輯錯誤無法被編譯器檢測到!相反,該程序具有未定義的行爲,其中可能包括運行看似正常,崩潰或產生各種垃圾。有很多的(我不能強調足夠的一樣,很多)導致未定義行爲的情況

+1

「無法檢測到」 - 總的來說:是的。在這種情況下:肯定是可行的。 –

+0

@KarolyHorvath - 這就是'Lint'的用途...... –

+0

其實如果我改變自由刪除亞軍,它也是正確的。 我可以問問原因可能是空閒或刪除只是告訴你內存是否可用實際上沒有清除數據裏面,所以你也可以訪問Next。 我可以問一下如何改善它嗎? – Hypnoz

1

你的程序可以正常工作因爲free()不僅標誌着一些內存爲免費的,但它不實際上會覆蓋它。因此,機會是您的解決方案將在大多數時間正確運行,因爲在您的功能中您沒有使用任何新內存。 (至少在單線程環境)

在另一方面,我會去和從根本上改變這樣的功能:

template<typename _Tp> 
void unique(forward_list<_Tp>& list) 
{ 
    unordered_map<_Tp, bool> record; 
    auto la=list.before_begin(); 
    for(auto it=list.begin(); it!=list.end(); ++it) 
    { 
    if(record.find(*it)==record.end()) 
     record[*++la] = true; 
    else 
     list.erase_after(la); 
    } 
} 

,你甚至可以去儘量寫的:

template<typename _Tp> 
void unique(forward_list<_Tp>& list) 
{ 
    unordered_map<_Tp, bool> record; 
    auto la=list.before_begin(); 
    for(auto e: list) 
    { 
    if(record.find(e)==record.end()) 
     record[*++la] = true; 
    else 
     list.erase_after(la); 
    } 
} 

但我認爲這可能有點太過分,因爲它並不反映我們需要一個接一個地接一個元素。


我對根本性變化的原因:

  1. 在C++ free()被稱爲delete。它與new(用於C++而不是malloc()calloc())配對使用。 delete這樣使用:

    刪除亞軍;
    //和new是這樣使用的:
    Some_type * p = new Some_type();

  2. STL已經有一個LinkedList,所以使用它是有意義的。它被稱爲std::forward_list。您想使用erease_after, with a nice example

  3. 你想使用std :: unsorted_map而不是hash_map(同樣,因爲它是在STL中)。最好的永遠是標準的解決方案。

  4. 一個類的主要目的是爲了躲遠必要的指針活動,所以在功能上頭,我寧願使用引用代替指針,這樣至少你的功能應該是

    無效removeDuplicateWithHashtable(LinkedListElement &頭)

+0

「我們使用引用而不是指針」 - 公平地說,使用指針是完全有效的C++。 – mathematician1975

+0

我不同意。因爲我們有shared_ptr和unique_ptr,指針可以在非庫代碼中始終避免。我希望你喜歡我的示例代碼;) –

+0

此外,在函數頭中使用指針是相當混亂的:你不知道你是否需要在指針之後調用delete ... –

相關問題