我正在尝试编写一个弹出列表中最后一个元素的函数,但是我一直错误地指向非法的de引用。我在这做错了什么?从插入函数中获取分段错误,代码就在底部。任何帮助表示赞赏。
这是我的PopBack功能
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()
此处还有我正在调用的功能
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;
}
这是我的插入功能
// 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;
}
这是我的结束功能
// 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;
}
这是我的空函数
template < typename T >
bool List<T>::Empty() const
{
return (first_ == 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_;
}
答案 0 :(得分:0)
如果您的List有一个元素,我假设SomeClass.include(Module)
和first_
都指向该元素。那么当List包含恰好一个元素时调用PopBack会发生什么:
last
也许你可以这样做:
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;
}
答案 1 :(得分:0)
方法PopBack
在first_等于last_时具有未定义的行为,因为最初两个节点都设置为0
if (first_ == last_)
first_ = last_ = 0;
然后您尝试访问数据成员next
以获取等于0的节点
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()
方法Insert
我理解内存泄漏,因为首先分配一个节点,并将其地址分配给newLink
Link* newLink = NewLink(t);
然后重新分配此变量
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;
}