某些编译器抛出的分段错误错误,用于实现链表

时间:2020-06-23 22:11:42

标签: c++ data-structures linked-list iterator segmentation-fault

我通过以下主要功能遇到细分错误。 头文件具有一个链表实现,其中包含一个迭代器类和不同的测试成员。

问题是分段错误错误出现在某些编译器上,而在其他编译器上消失了。我尝试使用GDB调试任何错误,但程序执行正常。

这真的让我很烦,因为我找不到引起分段错误的原因。

非常感谢您的帮助。

编辑: 我注意到,使用此更新的main,逻辑存在缺陷,并且不会在指定位置插入节点。因此,我将不得不进行更多调试才能找出问题所在。

似乎执行了else if中的insert()块而不是else块。

Main.cpp


#include <iostream>
#include "List.h"

int main(){

    List<double> l;

    l.push_back(1.1);
    l.push_back(2.2);
    l.insert(l.begin()++, 3.3);

    l.printList();
}

List.h

#include <cstdint>
#include <iostream>
#include <memory>

template<typename T>
class List
{
public:

    class Node {
    public:
        Node(T value) : value_(value) {}

        Node(T value, Node* prev, Node* next) : value_(value), prev_(prev), next_(next) {}

        T value_;
        Node* next_;
        Node* prev_;
    };

    Node* head_;
    Node* tail_;

    //! An iterator over the list
    class iterator
    {
    public:

        Node* iNode;
        iterator(Node* head): iNode(head){ }
        ~iterator() {}


        T& operator*() {
            return  iNode -> value_;
        }
    
        iterator& operator++() {
            iNode = iNode->next_;
            return *this;
        }

        iterator operator++(int ignored) {
            iNode = iNode->next_;
            return *this;
        }

        iterator& operator--() {
            iNode = iNode->prev_;
            return *this;
        }

        //! Is this iterator pointing at the same place as another one?
        bool operator== (const iterator& it) const {
            return this->iNode == it.iNode;
        }

        //! Is this iterator pointing at a different place from another?
        bool operator!= (const iterator& it) const {
            return this->iNode != it.iNode;
        }
    };

    //! Default constructor
    List() :tail_(nullptr) {}


    void push_back_node(T value)
    {
        Node* newnode = new Node(value, tail_, nullptr); //make and link new tail node
        if (tail_)
        {
            tail_->next_ = newnode; // link in new node
        }
        else
        {
            head_ = newnode;
        }
        tail_ = newnode; // update tail
    }

    //! Copy constructor
    List(const List& lst) : head_(nullptr), tail_(nullptr)
    {
        Node* cur = lst.head_; //get first source item.
        while (cur) // if there is a source item to copy
        {
            push_back_node(cur->value_); // stick the item on the end of this list
            cur = cur->next_; // get next source item
        }
    }

    void clear()
    {
        while (head_)
        {
            delete std::exchange(head_, head_->next_);
        }
        tail_ = head_;
    }


    //! Copy assignment operator
    List& operator= (const List& list_copy) {
        List tmp(list_copy);
        clear();
        std::swap(*this, tmp);
        return *this;
    }
    
    //! Move constructor
    List(List&& move) {
        head_ = std::move(move.head_);
        tail_  = std::move(move.tail_);
    }

    ////! Move assignment operator
    List& operator= (List&& list) {     
        head_ = std::move(list.head_);
        tail_ = std::move(list.tail_);
        return *this;
    }

    //! Destructor
    ~List() {}

    //
    // Accessors:
    //
    //! How many elements are in this list?
    size_t size() const {
        size_t size = 0;

        auto temp = head_;

        while (temp != nullptr)
        {
            size++;
            temp = temp->next_;
        }
        return size;
    }

    //! Is this list empty?
    bool empty() const {
        return tail_ == nullptr && head_ == nullptr;
    }

    //! Get an iterator to the beginning of the list
    iterator begin() {
        return List<T>::iterator(head_);
    }

    //! Get an iterator just past the end of the list
    iterator end() {
        return List<T>::iterator(tail_);
    }

    //
    // Mutators:
    //
    //! Copy an element to the front of the list
    void push_front(const T& value) {
        
        Node* node = new Node(value);

        if (head_ == nullptr) {
            head_ = node;
        }
        else {
            node->next_ = head_;
            head_ = node;
        }
    }

    //! Move an element to the front of the list
    void push_front(T&& value) {

        Node* node = new Node(value);

        if (head_ == nullptr) {
            head_ = node;
        }
        else {
            node->next_ = head_;
            head_ = node;
        }
    }

    //! Copy an element to the back of the list
    void push_back(const T& value) {

        Node* node = new Node(value);
        if (tail_) {
            tail_->next_ = node;
            tail_ = tail_->next_;
        }
        else {
            head_ = node;
            tail_ = head_;
        }
    }

    //! Add an element to the back of the list
    void push_back(T&& value) {

        Node* node = new Node(value);
        if (tail_) {
            tail_->next_ = node;
            tail_ = tail_->next_;
        }
        else {
            head_ = node;
            tail_ = head_;
        }
    }

    iterator insert(iterator position, const T& value) {

        Node* newNode = new Node(value);

        if (position == List<T>::iterator(head_)) {
            newNode->next_ = head_;
            head_ = newNode;
        }
        else if (!position.iNode->next_) {
            position.iNode->next_ = newNode;
        }
        else {
            Node* curr = head_;
            while (curr->next_ != position.iNode)
            {
                curr = curr->next_;
            }

            newNode->next_ = curr->next_;
            curr->next_ = newNode;
        }

        return position;
    }

    void printList() const{

        auto node = head_;

        while (node != nullptr)
        {
            std::cout << node -> value_ << " ";
            node = node->next_;
        }
    }

    iterator insert(iterator position, T&& value){
        
        Node* newNode = new Node(value);

        if (position == List<T>::iterator(head_)) {
            newNode->next_ = head_;
            head_ = newNode;
        }
        else if (!position.iNode->next_) {
            position.iNode->next_ = newNode;
        }
        else {
            Node* curr = head_;
            while (curr->next_ != position.iNode)
            {
                curr = curr->next_;
            }

            newNode->next_ = curr->next_;
            curr->next_ = newNode;
        }
        
        return position;
    }

    //! Remove an element from an arbitrary location
    void erase(iterator it) {
        
        Node* temp = it.iNode->next_;
        // Copy data of the next node to current node 
         it.iNode->value_ = it.iNode->next_->value_;
        // Perform conventional deletion 
         it.iNode->next_ = it.iNode->next_->next_;
        free(temp);
    }
};


1 个答案:

答案 0 :(得分:1)

Node(T value) : value_(value) {}

没有将prev_next_指向有用的地方,所以

Node* node = new Node(value);

会生成一个定时炸弹节点,除非您稍后将其prev_next_成员设置为指向安全的地方。 push_back不会这样做。

解决方案:

使用

Node(T value, Node* prev, Node* next) : value_(value), prev_(prev), next_(next) {}

相反:

Node* node = new Node(value, nullptr, nullptr);

您将在push_backpush_frontinsert的所有变体中发现类似的缺陷。您还可以使用Node(T value, Node* prev, Node* next)构造函数来简化一些添加,推送和插入节点的工作,方法是使用周围的节点代替nullptr

相关问题