簡體   English   中英

雙向鏈表插入方法

[英]Doubly linked list insert method

我目前正在做一項學習雙向鏈表和迭代器的作業。 我正在制作一個insert()方法,它接受迭代器類型以及要添加到列表中的數據。 但是,我在insert()方法中標記的那一行出現異常,它說:

拋出異常:讀取訪問沖突。 iter.node 是 0xFFFFFFFFFFFFFFEF

我不確定這是迭代器還是鏈表的問題:

#include <cstdlib>
#include <iostream>
using namespace std;

class List {
    struct Node {
        int data;
        Node* next = nullptr;;
        Node* prev = nullptr;
    };

    friend ostream& operator<<(ostream& os, const List& rhs);

public:

    class iterator {
        friend class List;

        Node* node = nullptr;

    public:
        iterator(Node* node) : node(node) {}

        iterator& operator++() {
            node = node->next;
            return *this;
        }

        iterator& operator--() {
            node = node->prev;
            return *this;
        }

        bool operator==(const iterator& rhs) {
            if (node != rhs.node) {
                return false;
            }
            return true;
        }

        bool operator!=(const iterator& rhs) {
            return !(*this == rhs);
        }

        int operator*() const {
            return node->data;
        }

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

    List() {
        header = new Node();
        trailer = new Node();
        header->next = trailer;
        header->prev = nullptr;
        trailer->prev = header;
        trailer->next = nullptr;
    }

    void push_back(int data) {
        Node* newNode = new Node();
        newNode->data = data;
        newNode->prev = trailer->prev;
        newNode->prev->next = newNode;
        newNode->next = trailer;
        trailer->prev = newNode;
    }

    void pop_back() {
        Node* tempNode = trailer->prev->prev;
        tempNode->next = trailer;
        trailer->prev = tempNode;
    }

    void push_front(int data) {
        Node* newNode = new Node();
        newNode->data = data;
        header->next->prev = newNode;
        newNode->next = header->next;
        newNode->prev = header;
        header->next = newNode;
    }

    void pop_front() {
        Node* tempNode = header->next->next;
        tempNode->prev = header;
        header->next = tempNode;
    }

    int& front() {
        if (header->next == trailer) {
            cerr << "List is empty" << endl;
        }
        return header->next->data;
    }

    int& back() {
        if (trailer->prev == header) {
            cerr << "List is empty" << endl;
        }
        return trailer->prev->data;
    }

    int front() const {
        if (header->next == trailer) {
            cerr << "List is empty" << endl;
        }
        return header->next->data;
    }

    int back() const {
        if (trailer->prev == header) {
            cerr << "List is empty" << endl;
        }
        return trailer->prev->data;
    }

    int size() const {
        int count = 0;
        for (iterator i = begin(); i != end(); ++i) {
            ++count;
        }
        return count;
    }

    int& operator[](int index) {
        int ind = 0;
        for (iterator i = begin(); i != end(); ++i) {
            if (ind == index) {
                return i.node->data;
            }
            ++ind;
        }
    }

    int operator[](int index) const {
        int ind = 0;
        for (iterator i = begin(); i != end(); ++i) {
            if (ind == index) {
                return i.node->data;
            }
            ++ind;
        }
    }

    iterator& begin() {
        iterator iter(header->next);
        return iter;
    }

    iterator& end() {
        iterator iter(trailer);
        return iter;
    }

    iterator begin() const {
        iterator iter(header->next);
        return iter;
    }

    iterator end() const {
        iterator iter(trailer);
        return iter;
    }

    iterator& insert(iterator& iter, int data) {
        Node* newNode = new Node();
        newNode->data = data;
        iter.node->prev->next = newNode; //exception is thrown on this line
        newNode->prev = iter.node->prev;
        newNode->next = iter.node;
        iter.node->prev = newNode;
        iterator newIter(newNode);
        return newIter;
    }

    void clear() {
        Node* iter = header->next;
        Node* next;
        while (iter != trailer) {
            next = iter->next;
            delete iter;
            iter = nullptr;
            iter = next;
        }
        header->next = trailer;
        trailer->prev = header;
    }

    iterator& erase(iterator& iter) {
        for (iterator i = ++begin(); i != end(); ++i) {
            if (i == iter) {
                Node* tempNode = i.node;
                tempNode->prev->next = tempNode->next;
                tempNode->next->prev = tempNode->prev;
                delete tempNode;
                tempNode = nullptr;
                return ++i;
            }
        }
    }

public:
private:
    Node* header;
    Node* trailer;
};

ostream& operator<<(ostream& os, const List& rhs) {
    for (int i : rhs) {
        os << i << " ";
    }
    os << endl;
    return os;
}

void printListInfo(const List& myList) {
    cout << "size: " << myList.size()
        << ", front: " << myList.front()
        << ", back(): " << myList.back()
        << ", list: " << myList << endl;
}

int main() {
    List myList;
    for (int i = 0; i < 10; ++i) myList.insert(myList.end(), i * i);
    printListInfo(myList);
    myList.clear();
    for (int i = 0; i < 10; ++i) myList.insert(myList.begin(), i * i);
    printListInfo(myList);
}

iterator& iterator::begin()iterator& iterator::end()返回對局部變量的引用。 由於正是這些函數通過myList.insert(myList.begin(), ..)等傳遞給 main 中的List::insert(...) ,因此插入 function 總是在無效的迭代器上運行。

類似地, iterator::insert有一個類似的問題,它通過引用返回局部變量:

iterator& insert(...)
{
    ...
    iterator newIter(newNode);
    return newIter;
}

一旦這些函數退出,局部變量將被銷毀,因此返回的那些引用將懸空 - 指向 memory,而 object 曾經是。

一個快速修復方法是確保這些新迭代器不是 function 的本地迭代器,而是在堆上初始化,例如

iterator& begin() {
    iterator* iter = new iterator(header->next);
    return *iter;
}

iterator& end() {
    iterator* iter = new iterator(trailer);
    return *iter;
}

但是,這也意味着您必須引入一種方法來跟蹤這些迭代器,以便在不再需要迭代器時可以釋放 memory,可能是通過將迭代器存儲為List的成員變量而不是存儲 begin /end ListNode s,因此只能通過iterator s 訪問Nodes


我發現這是由於編譯時帶有警告,強烈推薦!

In member function 'List::iterator& List::begin()':
<source>:151:16: warning: reference to local variable 'iter' returned [-Wreturn-local-addr]
  151 |         return iter;
      |                ^~~~
<source>:150:18: note: declared here
  150 |         iterator iter(header->next);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM