Создание выходов LinkedList с кодом возврата -11 (SIGSEGV) - PullRequest
1 голос
/ 24 февраля 2020

Поэтому я пытаюсь создать класс Linked List, чтобы лучше понять, как работают указатели и структуры данных, но я продолжаю сталкиваться с ошибкой -11 SIGSEGV. Когда я посмотрел на ошибку, она сказала, что я могу использовать разыменованные указатели или получить доступ к массиву за его пределами, но ни один из них не имеет смысла для моей программы. Я везде искал похожие проблемы, но ни одна из них, похоже, не относится к моей программе. Кто-нибудь еще может увидеть, что я делаю не так?

#include <stdexcept>
#pragma once
using namespace std;

#define NODE typename LinkedList<T>::Node*

template <typename T>
class LinkedList {
public:
    void AddHead(const T& data); //Adds new node to the beginning of the list
    void AddTail(const T& data); //Adds new node to the end of the list
    LinkedList(); //Default constructor
    LinkedList(const LinkedList<T>& list); //Copy constructor

    struct Node {
        /*Individual node that stores the data*/
        T data;
        Node* prev;
        Node* next;
        Node(); //Default constructor for node
        Node(T _data); //Data constructor for node
        Node(T _data, Node* _prev, Node* _next); //Full constructor for node
    };
private:
    NODE head = nullptr;
    NODE tail = nullptr;
    unsigned int count;

};

/*Function definitions*/

template <typename T>
void LinkedList<T>::AddHead(const T& data) {
    NODE tempRef = new Node(data, nullptr, head);
    head->prev = tempRef;
    head = tempRef;
    delete tempRef;
    count++;
}

template <typename T>
void LinkedList<T>::AddTail(const T& data) {
    NODE tempRef = new Node(data, tail, nullptr);
    tail->next = tempRef;
    tail = tempRef;
    delete tempRef;
    count++;
}

template <typename T>
LinkedList<T>::LinkedList() {
    count = 0;
    head = nullptr;
    tail = nullptr;
}

template <typename T>
LinkedList<T>::LinkedList(const LinkedList<T>& list) {
    this->head = list.head;
    this->tail = list.tail;
    this->count = list.count;
}

/*Node Constructors*/

template <typename T>
LinkedList<T>::Node::Node() {
    next = nullptr;
    prev = nullptr;
}

template <typename T>
LinkedList<T>::Node::Node(T _data) {
    next = nullptr;
    prev = nullptr;
    data = _data;
}

template <typename T>
LinkedList<T>::Node::Node(T _data, Node* _prev, Node* _next) {
    next = _next;
    prev = _prev;
    data = _data;
}

Ответы [ 2 ]

0 голосов
/ 24 февраля 2020

Обе функции AddHead и AddTail имеют серьезную ошибку, поскольку выделенный узел сразу удаляется

head = tempRef;
delete tempRef;

и

tail = tempRef;
delete tempRef;

Таким образом, указатели головы и хвоста имеют недопустимые значения.

Кроме того, функции не обновляют tail и head соответственно в каждой функции.

И первоначально оба указателя равны nullptr. Таким образом, эти операторы

head->prev = tempRef;

и

tail->next = tempRef;

приводят к неопределенному поведению.

Функция AddHead может быть определена следующим образом

template <typename T>
void LinkedList<T>::AddHead(const T& data) {
    NODE tempRef = new Node(data, nullptr, head);

    if ( head == nullptr )
    {
        head = tail = tempRef;
    }
    else
    {
        head = head->prev = tempRef;
    }

    count++;
}

И функция AddTail может выглядеть следующим образом:

template <typename T>
void LinkedList<T>::AddTail(const T& data) {
    NODE tempRef = new Node(data, tail, nullptr);

    if ( tail == nullptr )
    {
        tail = head = tempRef;
    }
    else
    {
        tail = tail->next = tempRef;
    }

    count++;
}

Конструктор копирования (и оператор присваивания копии) либо должен быть определен как удаленный, либо должен сделать глубокую копию списка, переданного в качестве аргумента. .

В противном случае два списка будут пытаться удалить одни и те же узлы два раза (в забытом вами деструкторе).

Структура Node должна быть объявлена ​​как член частного класса.

0 голосов
/ 24 февраля 2020

Вы delete узлы, которые вы добавляете в список в AddTail и AddHead. Это оставляет указатели на мусор в списке.

Кроме того, не ясно, как использовать ваш связанный список. Вы не можете позвонить AddHead, если head равно nullptr (потому что AddHead разыменовывает head), и вы не можете позвонить AddTail, если tail равно nullptr. Поскольку ваш конструктор устанавливает head и tail равными nullptr, что вы можете делать дальше?

Если для head допустимо быть nullptr, почему AddHead делает head->prev = tempRef; без проверки, является ли head nullptr?

Я настоятельно призываю вас документировать свой код. Например, каковы необходимые предварительные условия для вызова AddHead? Должно ли быть безопасно звонить, если head - это nullptr, или это требование не должно быть? Почему это не задокументировано?

...