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

Segmentation fault error thrown with certain compilers for linked list implementation

我在使用以下主要功能时遇到分段错误。 头文件有一个链表实现,带有一个迭代器class和不同的测试成员

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

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

非常感谢任何帮助。

编辑: 我注意到这个更新后的 main 逻辑有缺陷,没有在指定位置插入节点。因此,我将不得不进行更多调试以找出问题所在。

似乎执行了 insert() 中的 else if 块而不是 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);
    }
};


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) 构造函数通过使用周围节点代替 nullptrs

来简化一些添加、推送和插入节点的工作