C++ 单链表-弹出功能

C++ 单链表-弹出功能,c++,linked-list,singly-linked-list,C++,Linked List,Singly Linked List,我试图编写一个函数,弹出列表中的最后一个元素,但我不断收到一个错误,指向非法的指针反引用。我做错了什么?我的插入函数也有分段错误,代码在底部。感谢您的帮助 这是我的弹出式功能 template < typename T > void List<T>::PopBack() { if (Empty()) { std::cerr << "** List error: PopBack() called on empty list\n"; ret

我试图编写一个函数,弹出列表中的最后一个元素,但我不断收到一个错误,指向非法的指针反引用。我做错了什么?我的插入函数也有分段错误,代码在底部。感谢您的帮助

这是我的弹出式功能

template < typename T >
void List<T>::PopBack()
{
  if (Empty())
  {
    std::cerr << "** List error: PopBack() called on empty list\n";
    return;
  }

  Link *oldLink = last_;

  if (first_ == last_)
    first_ = last_ = 0;

    Link *currLink = GetPred(last_);

    last_ = currLink;
    last_->next_ = nullptr;

    delete oldLink;

} // end PopBack()
模板
void List::PopBack()
{
if(空())
{
标准::cerr next_uu=nullptr;
删除旧链接;
}//结束PopBack()
这里还有我正在调用的函数

template <typename T >
typename List<T>::Link* List<T>::GetPred ( Link* x )
{
  Link* p = first_;
  while ( p != nullptr && p->next_ != x )
    p = p->next_;
  return p;
}
模板
类型名称列表::链接*列表::GetPred(链接*x)
{
Link*p=第一个;
while(p!=nullptr&&p->next\ux)
p=p->next;
返回p;
}
这是我的插入函数

// Insert t at (in front of) i; return i at new element
template < typename T >
ListIterator<T> List<T>::Insert (ListIterator<T> i, const T& t)
{
  if (Empty())  // always insert
  {
    i = End();
  }
  if (!i.Valid()) // null
  {
    std::cerr << " ** cannot insert at position -1\n";
    return End();
  }
  Link* newLink = NewLink(t);
  Link* currLink = GetPred(i.curr_);

  // leave i at new entry and return
  newLink = currLink;
  return i;
}
//在i前面插入t;在新元素处返回i
模板
ListIterator列表::插入(ListIterator i,常量T&T)
{
if(Empty())//始终插入
{
i=结束();
}
如果(!i.Valid())//null
{
标准:cerr
ListIterator列表::End()
{
迭代器i(上一个->下一个);
返回i;
}
这是我的有效函数

// return iterator "1 past the back"
template < typename T >
ListIterator<T>  List<T>::End()
{
  Iterator i(last_->next_);
  return i;
}
// test cursor for legal dereference
template < typename T >
bool ConstListIterator<T>::Valid() const
{
  return curr_ != nullptr;
}
//合法解除引用的测试游标
模板
bool ConstListIterator::Valid()const
{
返回电流=空PTR;
}
这是我的空函数

template < typename T >
bool List<T>::Empty()  const
{
  return (first_ == nullptr);
}
模板
bool List::Empty()常量
{
返回值(第一个=nullptr);
}
检索方法

template < typename T >
T&  ConstListIterator<T>::Retrieve() const
// Return reference to current t
// note conflicted signature - const method returns non-const reference
{
  if (curr_ == nullptr)
  {
    std::cerr << "** Error: ConstListIterator<T>::Retrieve() invalid dereference\n";
    exit (EXIT_FAILURE);
  }
  return curr_->Tval_;
}
模板
T&ConstListIterator::Retrieve()常量
//返回对当前t的引用
//注意冲突签名-const方法返回非const引用
{
if(curr_==nullptr)
{
标准::cerr Tval_;
}

如果您的列表有一个元素,我假设
first
last
都指向该元素。那么当列表只包含一个元素时调用PopBack时会发生什么情况:

template < typename T >
void List<T>::PopBack()
{
  if (Empty())  // Not empty so don't take the if
  {
    std::cerr << "** List error: PopBack() called on empty list\n";
    return;
  }

  Link *oldLink = last_;

  // first_ and last_ are the same so set them to 0
  if (first_ == last_)
    first_ = last_ = 0;  // Why 0 instead of nullptr ?

    // GetPred(0) will return nullptr, i.e. currLink  will be nullptr
    Link *currLink = GetPred(last_);

    // Last will be nullptr
    last_ = currLink;

    // Dereference of nullptr !!!!
    last_->next_ = nullptr;

    delete oldLink;

}
模板
void List::PopBack()
{
if(Empty())//不是空的,所以不要使用if
{
标准::cerr next_uu=nullptr;
删除旧链接;
}
也许你可以:

template < typename T >
void List<T>::PopBack()
{
  if (Empty())      {
    std::cerr << "** List error: PopBack() called on empty list\n";
    return;
  }

  delete last_; // No reason for oldLink - just delete right away
                // as you will not dereference last_ until it has
                // a new value

  if (first_ == last_)
  {
    first_ = last_ = nullptr;
  }
  else
  {
    Link *currLink = GetPred(last_);
    last_ = currLink;
    last_->next_ = nullptr;
  }    
}
模板
void List::PopBack()
{
if(空()){
标准::cerr next_uu=nullptr;
}    
}

当first_uu等于last_u时,方法
弹出式
具有未定义的行为,因为最初两个节点都设置为0

if (first_ == last_)
  first_ = last_ = 0;
然后您尝试访问ALREAD等于0的节点的数据成员
next

last_->next_ = nullptr;
该函数可以编写得更简单

template < typename T >
void List<T>::PopBack()
{
    if ( Empty() )
    {
        std::cerr << "** List error: PopBack() called on empty list\n";
        return;
    }

    Link *oldLink = last_;
    Link *currLink = GetPred( last_ );

    last_ = currLink;

    if ( last_ == nullptr )
    {
        first_ = last_;
    }
    else
    {
        last_->next_ = nullptr;
    }

    delete oldLink;

} // end PopBack()
然后重新分配这个变量

newLink = currLink;
看起来这个方法实际上没有插入任何东西

它可以如下所示

// Insert t at (in front of) i; return i at new element
template < typename T >
ListIterator<T> List<T>::Insert (ListIterator<T> i, const T& t)
{
    if (Empty())  // always insert
    {
        i = End();
    }

    if ( !i.Valid() ) // null
    {
        std::cerr << " ** cannot insert at position -1\n";
        return End();
    }

    Link* newLink = NewLink(t);
    newLink->next = i.curr;

    Link* currLink = GetPred( i.curr_ );

    if ( currLink == nullptr )
    {
        first_ = newLink;
    }
    else
    {
        currLink->next = newLink;
    }   

    i.curr = newLink;

    return i;
}
//在i前面插入t;在新元素处返回i
模板
ListIterator列表::插入(ListIterator i,常量T&T)
{
if(Empty())//始终插入
{
i=结束();
}
如果(!i.Valid())//null
{
标准:cerr next=i.curr;
Link*currLink=GetPred(i.curr);
如果(currLink==nullptr)
{
第一个=新链接;
}
其他的
{
currLink->next=newLink;
}   
i、 curr=newLink;
返回i;
}

请发布准确的错误消息同时发布End()、Valid()、Empty()函数。@jpo38**error:ConstListIterator::Retrieve()无效的取消引用,这是我在尝试从列表中弹出反向链接时遇到的错误。我在编译时没有收到任何错误。那么为什么不发布
Retrieve()
code then?@maxpain121:请发布一个MCVE:我可以问一下为什么GetPred返回一个nullptr吗?我是不是从一开始就给它一个nullptr?我对链表还是很陌生,唯一需要做的是一个双链表实现,它更容易实现,因为我可以使用prev指针。您刚刚完成了
first\u=last\u0;
在调用GetPred之前的PopBack中。因此GetPred将返回NullPtrTank you,我将尝试这些,看看是否有效!我肯定在其他地方有错误,因为每次在测试工具中调用PopBack时,我都会得到**错误:ConstListIterator::Retrieve()无效的取消引用,然后程序终止。我在没有任何元素、1个元素、2个元素等的情况下尝试了此操作,每次都会出现这种情况。@maxpain121我指出了您显示的函数中的错误。对于我没有看到的代码,我不能说什么。
// Insert t at (in front of) i; return i at new element
template < typename T >
ListIterator<T> List<T>::Insert (ListIterator<T> i, const T& t)
{
    if (Empty())  // always insert
    {
        i = End();
    }

    if ( !i.Valid() ) // null
    {
        std::cerr << " ** cannot insert at position -1\n";
        return End();
    }

    Link* newLink = NewLink(t);
    newLink->next = i.curr;

    Link* currLink = GetPred( i.curr_ );

    if ( currLink == nullptr )
    {
        first_ = newLink;
    }
    else
    {
        currLink->next = newLink;
    }   

    i.curr = newLink;

    return i;
}