【问题标题】:Implement custom Iterator and const_iterator for doubly linked list in c++在 C++ 中为双向链表实现自定义 Iterator 和 const_iterator
【发布时间】:2018-12-13 22:33:52
【问题描述】:

这是我对双链表的iteratorconst_iterator 的实现。程序有强制性测试。当我运行我的程序时,我从测试中得到错误:

“递减运算符将迭代器向后移动,前缀”,由于 致命错误条件:SIGSEGV - 分段违规信号

我做错了什么?

test.cpp // 这是我得到错误的测试文件 //

TEST_CASE("Decrement operator moves the iterator backward", "[stage2]") {
    list l;
    append_to_list(l, { 5.55, 6.66, 7.77, 8.88 });

    auto it = l.end();
    SECTION("Prefix") {
        REQUIRE(*(--it) == 8.88);
        REQUIRE(*(--it) == 7.77);
        REQUIRE(*(--it) == 6.66);
        REQUIRE(*(--it) == 5.55);
        REQUIRE(it == l.begin());
    }

    SECTION("Postfix") {
        it--;
        REQUIRE(*(it--) == 8.88);
        REQUIRE(*(it--) == 7.77);
        REQUIRE(*(it--) == 6.66);
        REQUIRE(*it == 5.55);
        REQUIRE(it == l.begin());
    }
}

TEST_CASE("Decrement operator moves the (const) iterator backward", "[stage2]") {
    list l;
    append_to_list(l, { 5.55, 6.66, 7.77, 8.88 });

    auto it = l.cend();
    SECTION("Prefix") {
        REQUIRE(*(--it) == 8.88);
        REQUIRE(*(--it) == 7.77);
        REQUIRE(*(--it) == 6.66);
        REQUIRE(*(--it) == 5.55);
        REQUIRE(it == l.cbegin());
    }

    SECTION("Postfix") {
        it--;
        REQUIRE(*(it--) == 8.88);
        REQUIRE(*(it--) == 7.77);
        REQUIRE(*(it--) == 6.66);
        REQUIRE(*it == 5.55);
        REQUIRE(it == l.cbegin());
    }
}

list.hpp

class list {
private:
    struct node {
        double val = 0;
        node* prev = nullptr;
        node* next = nullptr;
    };

    node* head = nullptr;
    node* tail = nullptr;
    size_t num_elements = 0;

public:

    class const_iterator {
        node* current_ptr = nullptr;
        const list* o_list = nullptr;
    public:
        using difference_type = std::ptrdiff_t;
        using iterator_category = std::bidirectional_iterator_tag;
        using value_type = const double;
        using reference = const double&;
        using pointer = const double*;

        const_iterator() = default;
        const_iterator(node* ptr, const list* gen);

        const_iterator& operator++();
        const_iterator operator++(int);
        const_iterator& operator--();
        const_iterator operator--(int);

        reference operator*() const;
        pointer operator->() const;

        bool operator==(const const_iterator& rhs) const;
        bool operator!=(const const_iterator& rhs) const;

        friend class list;
    };

    class iterator {
        node* current_ptr = nullptr;
        const list* o_list = nullptr;
    public:
        using difference_type = std::ptrdiff_t;
        using iterator_category = std::bidirectional_iterator_tag;
        using value_type = double;
        using reference = double&;
        using pointer = double*;

        iterator() = default;
        iterator(node* ptr, const list* gen);

        iterator& operator++();
        iterator operator++(int);
        iterator& operator--();
        iterator operator--(int);

        reference operator*() const;
        pointer operator->() const;

        operator const_iterator() const;

        bool operator==(const iterator& rhs) const;
        bool operator!=(const iterator& rhs) const;

        friend class list;
    };

list.cpp //我的迭代器和const_iterator的实现 //

list::iterator list::begin() {
        return list::iterator(head, this);
    }

    list::iterator list::end() {
        return list::iterator(tail->next, this);
    }

    list::const_iterator list::begin() const {
        return list::const_iterator(head, this);
    }

    list::const_iterator list::end() const {
        return list::const_iterator(tail->next, this);
    }

    list::const_iterator list::cbegin() const {
        return list::const_iterator(head, this);
    }

    list::const_iterator list::cend() const {
        return list::const_iterator(tail->next, this);
    }

    list::iterator::iterator(node *ptr, const list *gen) {
        this->current_ptr = ptr;
        this->o_list = gen;
    }

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

    list::iterator& list::iterator::operator--() { //here triggers error!!!
        current_ptr = this->current_ptr->prev;
        return *this;
    }

    list::iterator list::iterator::operator++(int)
    {
        iterator old(*this);
        ++(*this);
        return old;
    }

    list::iterator list::iterator::operator--(int)
    {
        iterator left(*this);
        --(*this);
        return left;
    }
    list::const_iterator& list::const_iterator::operator++() {
        current_ptr = current_ptr->next;
        return *this;
    }

    list::const_iterator& list::const_iterator::operator--() { //here triggers error!!!
        current_ptr = current_ptr->prev;
        return *this;
    }

    list::const_iterator list::const_iterator::operator++(int) {
        const_iterator old = *this;
        ++(*this);
        return old;
    }

    list::const_iterator list::const_iterator::operator--(int) {
        const_iterator old = *(this);
        --(*this);
        return old;
    }

【问题讨论】:

  • 哪一行代码触发了这个错误?你知道吗?
  • @DrewDormann 此错误在迭代器类和 const_iterator 的前缀减量运算符上触发。 (我已经在帖子中评论了这个错误)
  • 这会有所帮助,指出测试的哪 line 导致错误发生以及操作方法的哪 line(不仅仅是哪种方法)发生错误。从我的角度来看,这可能是一个愚蠢的问题,但是“append_to_list”实现在哪里。

标签: c++ data-structures linked-list operator-overloading doubly-linked-list


【解决方案1】:

问题是您使用 null node * 作为 end(),它无法与 operator-- 一起使用;没有办法减少它以到达列表的最后一个节点。

你需要使用其他东西作为你的结束标记,它可以让你回到列表——要么是列表上的一个假“节点”,它不是真实列表的元素,要么添加一个指向迭代器类的原始列表,因此当您减少 end() 迭代器时,您可以恢复列表中的最后一个节点。


由于您的迭代器已经有一个 o_list 指针,因此使用它是最简单的:

list::iterator& list::iterator::operator--() {
    current_ptr = current_ptr ? current_ptr->prev : o_list->tail;
    return *this;
}

【讨论】:

  • 我理解你,但我不知道如何解决这个问题。你能写出解决方案吗?
  • 您的迭代器有一个列表指针。如果当前节点为空,则使用它来获取尾节点。
猜你喜欢
  • 2015-05-16
  • 2020-04-03
  • 2014-03-18
  • 2017-05-03
  • 2016-07-26
  • 2021-11-18
  • 2011-06-03
  • 2015-01-16
相关资源
最近更新 更多