不维护迭代剂脱烯

Not maintaining iterator dereferenceability?

本文关键字:迭代 维护      更新时间:2023-10-16

这是双重链接列表的迭代器的第一次尝试:

dlist.h

#ifndef dlist_h
#define dlist_h
/* Node */
template <class Elem>
struct Link
{
    Link();
    Link (Link<Elem>* s, Link<Elem>* p, const Elem& v);
    Link (const Link<Elem>& src);
    Link<Elem>& operator= (const Link<Elem>& src);
    bool operator== (const Link<Elem>& src);
    bool operator!= (const Link<Elem>& src);
    void swap(Link<Elem>& src);
    Link* succ;
    Link* prev;
    Elem val;
};

//----------------------------------------------------------------------------
/* Doubly Linked List */
template <class Elem>
class List
{ 
public:
    class iterator;
    List();
    iterator begin() { return iterator(first, first, last); }
    iterator end() { return iterator(last, first, last); }
    void push_front(const Elem& v);
    Elem& front();
    size_t size(); 
    void print();
private:
    Link<Elem> *first;
    Link<Elem> *last;
};
//----------------------------------------------------------------------------
/* a range-checked bidirectional iterator */
template <class Elem>
class List<Elem>::iterator
{
public:
    iterator();                                         // default constructor
    iterator(Link<Elem>* c, Link<Elem>* b, Link<Elem>* e);                  
    iterator(const iterator& src);                      // copy constructor
    iterator operator= (const iterator& src);           // copy assignment 
    iterator& operator++();                             // incrementations
    iterator operator++(int);                           // postfix
    iterator& operator--();                             // decrementations
    iterator operator--(int);                           // postfix
    Elem& operator*();                                  // dereferenceable lvalue
    const Elem& operator*() const;                      // dereferenceable rvalue
    bool operator== (const iterator& b) const;          // equality comparisons
    bool operator!= (const iterator& b) const;
    void swap(iterator& src);
private:
    Link<Elem>* curr;
    Link<Elem>* begin;
    Link<Elem>* end;
};
#include "dlist.cpp"
#endif

dlist.cpp

//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>::Link()
    : succ(nullptr), prev(nullptr), val(Elem())
{
}
//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>::Link (Link<Elem>* s, Link<Elem>* p, const Elem& v)
    : succ(s), prev(p), val(v)
{
}
//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>::Link (const Link<Elem>& src)
   : succ(src.succ), prev(src.prev), val(src.val)
{
}
//-----------------------------------------------------------------------------
template <class Elem>
Link<Elem>& Link<Elem>::operator= (const Link<Elem>& src)
{
    Link<Elem> temp(src);
    swap(*this, temp);
    return *this;
}
//-----------------------------------------------------------------------------
template <class Elem>
bool Link<Elem>::operator== (const Link<Elem>& src)
{
    return succ = src.succ && prev = src.prev;
}
//-----------------------------------------------------------------------------
template <class Elem>
bool Link<Elem>::operator!= (const Link<Elem>& src)
{
    return !(*this == src);
}
//-----------------------------------------------------------------------------
template <class Elem>
void Link<Elem>::swap(Link<Elem>& src)
{
    std::swap(prev, src.prev);
    std::swap(succ, src.succ);
    std::swap(val, src.val);
}
//-----------------------------------------------------------------------------
template<class Elem>
void swap(Link<Elem>& lhs, Link<Elem>& rhs)
{
    lhs.swap(rhs);
}
//-----------------------------------------------------------------------------
template<class Elem> 
List<Elem>::List()
    : first(new Link<Elem>()), last(first)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
void List<Elem>::push_front(const Elem& v)
{  
    first = new Link<Elem>(first, nullptr, v); 
}
//-----------------------------------------------------------------------------
template<class Elem>
Elem& List<Elem>::front()
{
    return first->val; 
}
//-----------------------------------------------------------------------------
template<class Elem>
size_t List<Elem>::size() 
{
    size_t count = 0;
    for (iterator p = begin(); p != end(); ++p)
    {
        ++count;     
    }
    return count;
}
//-----------------------------------------------------------------------------
template<class Elem>
void List<Elem>::print()
{
    for (iterator p = begin(); p != end(); ++p)
    {
         std::cout << *p <<' ';  
    }
}
//-----------------------------------------------------------------------------
template<class Elem>
List<Elem>::iterator::iterator()
    : curr(nullptr), begin(nullptr), end(nullptr)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
List<Elem>::iterator::iterator(Link<Elem>* p, Link<Elem>* b, Link<Elem>* e)
    : curr(p), begin(b), end(e)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
List<Elem>::iterator::iterator(const iterator& src)
    : curr(src.curr), begin(src.begin), end(src.end)
{
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator List<Elem>::iterator::operator= (const iterator& src)
{
    iterator temp(src);
    this->swap(temp);
    return *this;
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator& List<Elem>::iterator::operator++()
{
    if (curr == end)
    {
        throw std::out_of_range("List<Elem>::iterator::operator++(): out of range!n");
    }
    curr = curr->succ;
    return *this; 
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator List<Elem>::iterator::operator++(int)
{
    if (curr == end)
    {
        throw std::out_of_range("List<Elem>::iterator::operator++(): out of range!n");
    }
    Link<Elem>* old = curr;
    curr = curr->succ;
    return old; 
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator& List<Elem>::iterator::operator--()
{ 
    if (curr == begin)
    {
        throw std::out_of_range("List<Elem>::iterator::operator--(): out of range!n");
    }
    curr = curr->prev;
    return *this; 
}
//-----------------------------------------------------------------------------
template<class Elem>
typename List<Elem>::iterator List<Elem>::iterator::operator--(int)
{ 
    if (curr == begin)
    {
        throw std::out_of_range("List<Elem>::iterator::operator--(): out of range!n");
     }
     iterator old(*this);
     curr = curr->prev; 
     return old; 
 }
//-----------------------------------------------------------------------------
template<class Elem>
Elem& List<Elem>::iterator::operator*() 
{ 
    return curr->val; 
}   
//-----------------------------------------------------------------------------
template<class Elem>
const Elem& List<Elem>::iterator::operator*() const
{  
    return curr->val;
}
//-----------------------------------------------------------------------------
template<class Elem> 
bool List<Elem>::iterator::operator== (const iterator& b) const
{ 
    return curr == b.curr; 
} 
//-----------------------------------------------------------------------------
template<class Elem>
bool List<Elem>::iterator::operator!= (const iterator& b) const
{ 
    return curr != b.curr; 
}
//-----------------------------------------------------------------------------
template<class Elem>
void List<Elem>::iterator::swap(iterator& src)
{
    std::swap(curr, src.curr); 
    std::swap(begin, src.begin);
    std::swap(end, src.end);
}
//-----------------------------------------------------------------------------
template<class Elem>
void swap(typename List<Elem>::iterator& lhs, typename List<Elem>::iterator& rhs)
{
    lhs.swap(rhs);
}

main.cpp

 #include <iostream>
 #include "dlist.h"
 /* simple test for iterator */ 
int main() 
{
    List<int> l;
    l.push_front(1);
    l.push_front(2);
    l.push_front(3);
    l.push_front(4);
    l.push_front(5);
    // default constructor, copy assignment
    List<int>::iterator p = l.begin();
    // lvalue dereferencing 
    *p = 100;
    // incrementation, rvalue dereferencing
    List<int>::iterator i;
    for (i = l.begin(); i != l.end(); ++i)
    {
        std::cout << *i <<' ';
    }
    if (i == l.end() && i != l.begin())
    {
        std::cout <<"ncomparison correct!n";
    }
    // postfix and prefix decrementation; maintain dereferenceability
    List<int>::iterator ii = l.end();
    --ii;
    for (; ii != l.begin(); ii--)
    {
        std::cout << *ii <<' ';
    } 
    return 0;
}

当它到达最后一个for循环时,减少operator--以某种方式使ii迭代器无效,尽管彻底 IMO 调试。

,我无法弄清楚。

这是一个可运行的样本。


问题是您的push_front方法,您忘了将first->succ->prev链接回新节点,因此您的双重链接列表基本上是单个链接的列表

第一个i--成功,因为last指向默认节点,但是curr->prev是一个NULLPTR,因为您忘记链接回去链接,因此下一个i--将deref deref nullptr curr导致错误。

修复您的push_front方法:

template<class Elem>
void List<Elem>::push_front(const Elem& v)
{
    first = new Link<Elem>(first, nullptr, v);
    first->succ->prev = first; //link back
}

您的Link构造函数无法正确更新给出的参数元素。插入两个元素之间的元素打破了先前的链接。

这是一个更合适的构造函数:

template <class Elem>
Link<Elem>::Link(Link<Elem>* s, const Elem& v)
    : succ(s), prev(s->prev), val(v)
{
    // Update next and previous nodes to make them aware of this
    s->prev = this;
    if(prev) prev->succ = this;
}

如果更新List::push_front以使用此构造函数,则会发现您的代码编译并运行。

您应该考虑在适当的情况下制作const以避免错误(或在bool operator== (const Link<Elem>& src) const的情况下发现现有的错误)。链接。