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. Тогда я понял, что вы только delete что вы new. Справедливо, но я new ING каждого 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 ed вне текущей области?

Во-вторых, free Пространство прекрасно работает, но, очевидно, это не так, потому что я не malloc, но new ed!

Что я делаю неправильно? Как правильно убить удаленный узел?

Edit1: Сделано это более описательный согласно ответам на мой пост Edit2: Правило 3 методов добавил

+0

[Возможно, полезно.] (Http://stackoverflow.com/q/33047452/472647) – CodeMouse92

+0

'~ Node() {delete next; delete prev; } 'будет убивать узлы вокруг него. Например, вы удаляете узел Y между узлами X и Z, связывая 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; 

На данный момент темп не был очищен так дальше и пред-прежнему указывают на два узла, которые используются, чтобы окружить пса и теперь связаны друг с другом. Это вызовет серьезные проблемы, если не для:

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

free терпит неудачу, потому что значение указывает временный вложен новый. Ответ NathanOliver имеет это покрыто, но скрывается под то, что будет происходить с

delete temp; 

это будет вызывать деструктор, чтобы очистить как хороший маленький объект. К сожалению Node деструктор выглядит следующим образом:

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

temp->next все еще указывает на живой узел. Также temp->prev.

Next and prev get delete d. Который называет их деструкторов, delete соединяет два узла, которые они касаются, и вызывает смертельный штурм, который уничтожит все узлы в списке.

Если двойные удаления не уничтожают программу в первую очередь. Каждый связанный узел попытается установить delete узел, который только deleted их. Нехорошо.

Коэффициенты довольно хороши, что деструктор Node должен просто следить за собой и оставить разрушение другого Node s классу LinkedList.

4

Вы не можете использовать free(), если выделенную память с new

Вы можете использовать malloc() с free() или new с delete. Вы также не должны использовать malloc() и free() с объектами, поскольку они не вызывать конструктор объектов и деструктор в отличие от new и delete

Так, так как вы выделили узлы с new мы можем изменить

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

в

delete temp; 
+0

Я получаю «Ошибка сегментации», когда я делаю «delete temp» – Yalda

+3

, тогда у вас есть проблема где-то в коде. Пожалуйста, предоставьте, скорее всего, [mcve] – NathanOliver

+1

@Yalda [Правило трех] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). –

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

Так почему я не позволил удалить то, что было где-то обновленного еще? Это потому, что оно появилось за пределами текущей сферы?

Вам разрешено delete вещей new ed в другом месте. Это не проблема, если вы указываете на действительный адрес. Сег-ошибка появляется, когда вы пытаетесь использовать один из указателей, указывающих на текущий адрес delete.

Во-вторых, освобождение пространства отлично работает, но я чувствую, что это как обман!

Вы должны использовать free только тогда, когда вы использовали malloc и delete, когда вы использовали new. Вы должны никогда смешать их. Кроме того, после того, как вы установили delete, перейдите в указатель NULL.

Поскольку мне могут потребоваться все, что нужно сделать для деструктора моего узла.

Класс, инкапсулирующий данные, должен также осуществлять собственное управление памятью. Например, LinkedList должен управлять памятью узлов.

Это означает, что если у вас есть что-то похожее на LinkedList<T>::add(Node<T> *data), вы должны вместо этого рассмотреть что-то вроде LinkedList<T>::add(T data); то сам класс списка заботится об обработке узлов.

В противном случае вы рискуете отправить узел new ed в список, затем в какой-то момент он будет внутренне в какой-то момент, но в другом месте клиент списка по-прежнему содержит ссылку на недействительный узел. Когда клиент пытается его использовать, снова bam !: seg-fault.

Что я делаю неправильно? Как правильно убить удаленный узел?

Кроме смешивания new с с free с, вероятно выдаёт ошибку сегментации, которые инициированы недопустимого доступа к памяти, так что вы должны найти указатель, который больше не указывает на действительный (deleted т.е. ООН) памяти.

1

Есть много ответов, заявляющих, что new/delete и malloc()/free() всегда должен быть соединены так, но я чувствую, что это должно быть сказано почему точно.

Как и в ваших инициализациях,

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

new ключевого слово возвращает полностью набранный указатель на объект объекта, определенный в самом заявлении, в то время как malloc() просто выделяет данное пространство памяти без присвоения типа, и таким образом возвращает void*.Кроме того, new/delete имеет дело с памятью из Free Store, а malloc()/free() выделяет/освобождает память в куче, хотя некоторые компиляторы могут реализовать new/free в терминах malloc()/free в некоторых случаях.

Также некоторое значение в том, что new и delete вызов конструктора и деструктора, соответственно, в то время как malloc() и free() просто выделить и освобождать память кучи, не обращая внимания на состояние самой памяти.