1

我試圖從鏈表中刪除重複項,並遇到了一個問題,這可能是顯而易見的,直接的,但我沒有在多年使用C++,但是我做不到通過閱讀SO上的類似問題來了解我做錯了什麼。分割故障(核心轉儲)當我刪除指針

下面是我的代碼部分。我刪除了不相關的部分(例如構造函數,其他方法等)。

template<class T> 
class Node { 
    Node() : data(NULL), next(NULL), prev(NULL) {} 
    explicit Node(T d) : data(d), next(NULL), prev(NULL) {} 
    explicit Node(T d, Node<T> *nxt, Node<T> *prv) : data(d), next(nxt), prev(prv) {} 
    ~Node() { delete next; delete prev; } 

    T data; 
    Node *next; 
    Node *prev; 
}; 

template<class T> 
class LinkedList { 
    LinkedList() : head(NULL) {} 
    explicit LinkedList(Node<T> *head_node) : head(head_node) {} 
    LinkedList& operator=(const LinkedList &copy_list); 
    ~LinkedList(); //didn't implement this but I guess delete head is all? 

    Node<T>* head; 
}; 


template<class T> 
LinkedList<T> RemoveDuplicates(const LinkedList<T> &linked_list) { 
    //my = overload creates a whole new list with the same data as the original one 
    LinkedList<T> result = linked_list; 

    Node<T> *cur = result.head; 
    Node<T> *prev = NULL; 

    while (cur) { 
    if (...) { //duplicate found 
     Node<T> *temp = cur; 
     prev->next = cur->next; 
     cur = cur->next; 
     cur->prev = prev; 
     free(temp); //Here is my problem!!! 
    } 
    else { 
     prev = cur; 
     cur = cur->next; 
    } 
    } 
    return result; 
} 

所以第一,我沒有delete temp和我Segmentation fault。然後我意識到你只有deletenew什麼。不夠公平,但我new荷蘭國際集團各Node建設main整個列表時:

Node<char> *h = new Node<char>('H'); //I have a constructor to handle this 
Node<char> *e = new Node<char>('E'); 
Node<char> *l1 = new Node<char>('L'); 
Node<char> *l2 = new Node<char>('L'); 
Node<char> *o = new Node<char>('O'); 

h->next = e; 
h->prev = NULL; 

e->next = l1; 
e->prev = h; 

//and so on 

那麼,爲什麼我不能delete東西,是new版別的地方?是否因爲在當前範圍之外是new

二,free ing的空間工作正常,但顯然不是正確的事情,因爲我沒有mallocnew ed!

我在做什麼錯?如何正確殺死刪除的節點?

EDIT1地:它根據回覆我的帖子 更具描述性EDIT2:3種方法規則添加

+0

[可能有用。](http://stackoverflow.com/q/33047452/472647) – CodeMouse92

+0

'〜Node(){delete next;刪除prev; }'會殺死它周圍的節點。例如,您可以從節點X和Z之間刪除節點Y,將X和Z鏈接起來。然後'刪除Y'來獲取它的資源。 Y的析構函數將破壞X和Z.X和Z的析構函數將破壞他們所觸及的所有元素,包括正在被破壞的X和Z.這是我們過去稱爲非常糟糕的場景。如果我是你,我會重新考慮析構邏輯。 – user4581301

回答

2

這是正確識別和解決OP的即時問題的其他答案的附錄。爲了解釋接下來會發生什麼,需要快速解決問題。

Node<T> *temp = cur; 
    prev->next = cur->next; 
    cur = cur->next; 
    cur->prev = prev; 

此時溫度尚未清除,所以next和prev仍然指向用於環繞CUR和現在連接在一起的兩個節點。如果不是因爲這會造成嚴重的問題:因爲該值指向臨時被新分配

free(temp); //Here is my problem!!! 

free失敗。 NathanOliver的回答有這個覆蓋,但潛伏的下方是將

delete temp; 

這發生將調用析構函數清理是一個不錯的小東西是什麼。不幸的是,Node析構函數看起來是這樣的:

~Node() { delete next; delete prev; } 

temp->next仍然指向一個活動節點。 temp->prev也是如此。

下一步和prev獲得delete d。其中調用它們的析構函數,delete它們觸摸的兩個節點,並調用一個將破壞列表中的所有節點的死亡風暴。

如果雙刪除不首先殺死程序。每個鏈接節點都會嘗試delete這個節點,它們只是deleted。不好。

機率很好,Node析構函數應該照顧自己,並將其他Node s的破壞保留到LinkedList類。

4

不能使用free()如果用new

分配的內存,您可以使用malloc()free()newdelete。你也應該不使用malloc()free()使用對象,因爲他們不調用對象的構造函數和析構函數不像newdelete

那麼既然你用new分配的節點,我們可以改變

free(temp); //Here is my problem!!! 

delete temp; 
+0

當我做'刪除臨時文件'時,我得到'Segmentation fault' – Yalda

+3

,那麼你在代碼中的某個地方有問題。請提供一個[mcve] – NathanOliver

+1

@Yalda [規則三](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-ree)最可能的問題。 –

2

在這種情況下,具有構造函數的代碼,同時也析構函數是非常重要的。

默認情況下,你應該在構造函數中使用的「新」,並在析構函數「刪除」。更具體地說,分配構造函數中所需的所有資源並在析構函數中釋放資源非常重要,這樣可以確保您沒有任何內存泄漏。

free(temp);//You don't need this, also you don't need delete. 

請發佈您的構造函數和析構函數代碼。

L.E:

我認爲你應該做這樣的事情:

template<class T> 
class LinkedList 
{ 
    private: 
    struct Node { 
     T m_data; 
     Node *m_next; 
     Node *m_prev; 
    }; 
    Node* m_first; 
    Node* m_last; 
    int m_count; 
    public: 
    LinkedList(); 
    ~LinkedList(); 
    T GetFirst(); 
    T GetLast(); 
    void AddNode(T node); 
    void RemoveAt(int index); 
    T GetAt(int index); 
    int Count(); 
}; 

//constructor 
template <typename T> 
LinkedList<T>::LinkedList(){ 
    m_count = -1;//-1 == "The list is empty! 
} 

template <typename T> 
void LinkedList<T>::AddNode(T data){ 
    Node* temp = new Node; //new is called only here -> delete is called in destructor or in RemoveAt 
    temp->m_data = data; 
    if (m_count > -1){//If the list contains one or more items 
     temp->m_next = m_first; 
     temp->m_prev = m_last; 
     m_last->m_next = temp; 
     m_last = temp; 
     m_count++; 
    } 
    else if (m_count == -1) 
    {//If no items are present in the list 
     m_first = temp; 
     m_first->m_next = temp; 
     m_first->m_prev = temp; 
     m_last = temp; 
     m_last->m_next = temp; 
     m_last->m_prev = temp; 
     m_count = 0; 
    } 
} 

template <typename T> 
void LinkedList<T>::RemoveAt(int index){ 
    if (index <= m_count)//verify this request is valid 
    { 
     Node* temp = m_last; 
     for (int i = 0; i <= index; ++i){ 
      temp = temp->m_next; 
     } 
     temp->m_prev->m_next = temp->m_next; 
     temp->m_next->m_prev = temp->m_prev; 
     delete temp; 
     m_count--; 
    } 
} 

template <typename T> 
T LinkedList<T>::GetAt(int index) 
{ 
    Node* temp = m_first; 
    if (index <= m_count && index > -1){ 
     int i = 0; 
     while(i < index){ 
      temp = temp->m_next; 
      i++; 
     } 
    } 
    return temp->m_data; 
} 

template <typename T> 
T LinkedList<T>::GetFirst() { 
    return m_first->data; 
} 

template <typename T> 
T LinkedList<T>::GetLast(){ 
    return m_last->data; 
} 

template <typename T> 
int LinkedList<T>::Count(){ 
    return m_count; 
} 

template <typename T> 
LinkedList<T>::~LinkedList(){ 
    while(m_count > -1){ 
     Node* temp = m_first; 
     m_first = temp->m_next; 
     delete temp;//delete in destructor 
     m_count--; 
    } 
} 
+0

謝謝,只是添加了那些!但是在內存中還有一些空間不再需要(或指向)。我怎樣才能不需要刪除它? – Yalda

+1

我看到你的問題,我正在爲你準備一些示例代碼。 – Heto

+0

我已經添加了一些關於我應該怎麼做的代碼。 – Heto

2

那麼,爲什麼我不可以刪除的東西,是newed地方 別的嗎?是因爲它在當前範圍之外被新出現嗎?

您被允許登錄deletenew東西在其他地方編輯。只要你指向一個有效的地址,這不是一個問題。當您嘗試使用指向now- delete ed地址的指針之一時,會出現seg-fault。

其次,釋放空間工作正常,但我覺得這就像作弊!

,才應使用free當你使用mallocdelete當你使用new。你應該從來沒有混合起來。此外,在delete之後,養成將NULL分配給指針變量的習慣。

因爲我可能需要在我的Node的析構函數上完成的事情。

封裝數據的類還應該在內部執行自己的內存管理。例如,LinkedList應該管理節點的內存。

這意味着,如果你有類似LinkedList<T>::add(Node<T> *data)的東西,你應該改爲像LinkedList<T>::add(T data);那麼列表類本身負責處理節點。

否則,您可能會冒險將new ed節點發送到列表中,然後列表delete在某個時間點內部發生,但是在其他地方,列表的客戶端仍持有對現在無效節點的引用。當客戶端嘗試使用它時,再次使用bam!:seg-fault。

我在做什麼錯?如何正確殺死刪除的節點?

除了new s的free小號混合,該段錯誤很可能是由一個無效的內存訪問觸發,所以你會發現,不再指向有效的(即未deleted)內存的指針。

1

有很多答案,指出new/deletemalloc()/free()應始終如此配對,但我認爲它應該確切的說爲什麼

在你的初始化,

Node<char> *h = new Node<char>('H'); 

new關鍵詞返回一個完全類型的對象對象的指針,在語句本身定義的,而malloc()只是分配一個指定的存儲空間而不指定類型,所以返回void*。此外,new/delete處理免費商店中的內存,而malloc()/free()在堆上分配/釋放內存,儘管在某些情況下,某些編譯器可能根據malloc()/free實施new/free

而且一些重要的是newdelete調用構造函數和析構函數分別,而malloc()free()簡單地分配和釋放堆內存,而不考慮內存本身的狀態。