分割故障(核心转储)当我删除指针

问题描述:

我试图从链表中删除重复项,并遇到了一个问题,这可能是显而易见的,直接的,但我没有在多年使用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://*.com/q/33047452/472647) – CodeMouse92

+0

'〜Node(){delete next;删除prev; }'会杀死它周围的节点。例如,您可以从节点X和Z之间删除节点Y,将X和Z链接起来。然后'删除Y'来获取它的资源。 Y的析构函数将破坏X和Z.X和Z的析构函数将破坏他们所触及的所有元素,包括正在被破坏的X和Z.这是我们过去称为非常糟糕的场景。如果我是你,我会重新考虑析构逻辑。 – user4581301

这是正确识别和解决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类。

不能使用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://*.com/questions/4172722/what-is-the-rule-of-ree)最可能的问题。 –

在这种情况下,具有构造函数的代码,同时也析构函数是非常重要的。

默认情况下,你应该在构造函数中使用的“新”,并在析构函数“删除”。更具体地说,分配构造函数中所需的所有资源并在析构函数中释放资源非常重要,这样可以确保您没有任何内存泄漏。

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

那么,为什么我不可以删除的东西,是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)内存的指针。

有很多答案,指出new/deletemalloc()/free()应始终如此配对,但我认为它应该确切的说为什么

在你的初始化,

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

new关键词返回一个完全类型的对象对象的指针,在语句本身定义的,而malloc()只是分配一个指定的存储空间而不指定类型,所以返回void*。此外,new/delete处理免费商店中的内存,而malloc()/free()在堆上分配/释放内存,尽管在某些情况下,某些编译器可能根据malloc()/free实施new/free

而且一些重要的是newdelete调用构造函数和析构函数分别,而malloc()free()简单地分配和释放堆内存,而不考虑内存本身的状态。