我们假设我只允许使用new
和delete
,并且在我的实施中没有智能指针。我没有使用哨兵节点。
以下是pop_back
的实施方式:
void sLinkedList::pop_back()
{
if(begin == nullptr)
{
std::cerr << "There is nothing to pop." << std::endl;
}
else
{
node* nodeToDelete = begin;
while(nodeToDelete->next != nullptr)
{
nodeToDelete = nodeToDelete->next;
}
delete nodeToDelete;
nodeToDelete = nullptr;
--mSize;
}
}
它的作用是创建一个指向节点nodeToDelete
的指针,它遍历整个列表,直到它到达最后一个节点(指向nullptr的节点)。然后我删除了最后一个节点,将其设置为等于nullptr,一切都应该没问题,因为此前的节点(以前是倒数第二个节点)现在指向nullptr,标记列表的末尾。
当我按照以下说明运行main时:
int main()
{
sLinkedList newList;
std::cout << "Length is " << newList.length() << std::endl;
newList.print();
newList.push_front(4);
std::cout << "Length is " << newList.length() << std:: endl;
newList.print();
newList.pop_back();
std::cout << "Length is " << newList.length() << std::endl;
newList.print();
}
我得到了输出:
Length is 0
The list is empty.
Length is 1
4
Length is 0
4 // should print "There is nothing to pop."
在第一个结果后直接添加另一个pop_back
会产生Aborted (core dumped)
信号。
为什么这个想法不起作用?
答案 0 :(得分:2)
好的,但是吗?
当你指定nodeToDelete = nodeToDelete-&gt; next时;你说你的本地指针nodeToDelete现在指向内存中与nodeToDelete-&gt; next相同的位置。两个指针之间没有其他关系。所以当你然后分配nodeToDelete = nullptr;你实际上什么都不做:那个本地指针永远不会被再次使用,所以它所指向的内存区域并不特别重要。
不幸的是,即使你删除了那个节点,应该是最终节点仍然指向它曾经的位置,所以你的下一个pop_back调用会愉快地迭代到无法访问的内存。
我假设这是作业,所以我可能不应该为你重写它。但你可以通过实际修改应该是最后一个节点来修复它,而不仅仅是它的下一个指针的本地副本。
当然,如果这是一个真实的项目,std :: forward_list可能有所帮助。 :v
答案 1 :(得分:1)
一切都应该没问题,因为此前的节点(以前是倒数第二个节点)现在指向nullptr,标记列表的末尾。
好的,但是吗?
当您指定nodeToDelete = nodeToDelete->next;
时,您表示您的本地指针nodeToDelete
现在引用内存中与nodeToDelete->next
相同的位置。两个指针之间没有其他关系。因此,当您分配nodeToDelete = nullptr;
时,您实际上什么都不做:本地指针永远不会再次使用,所以它指向的内存区域并不特别重要。
不幸的是,应该是最后一个节点仍然指向它以前的位置,即使你delete
那个节点,所以你的下一个pop_back
调用会愉快地迭代到无法访问的内存。
我假设这是作业,所以我可能不应该为你重写它。但您可以通过实际修改应该是最后一个节点来修复它,而不仅仅是它的next
指针的本地副本。
当然,如果这是一个真实的项目,std::forward_list
可能有所帮助。 :v