【发布时间】:2018-03-31 16:59:14
【问题描述】:
我在课堂上学习单链表堆栈,我遇到了这个 stackoverflow 页面,它给了我一些关于如何弹出节点的参考:
Pop function on Linked list stack
第一个答案使用以下代码弹出一个节点:
struct Node
{
int data;
Node *next;
};
int pop(Node *head)
{
while(head->next != NULL)
{
head = head->next;
}
int value;
Node *tmp;
tmp = new Node;
value = head->data;
tmp = head;
delete tmp;
return value;
}
第三个答案使用以下代码:
int pop( Node * &top )
{
int value = 0;
if ( top )
{
value = top->num;
Node *tmp = top;
top = top->next;
delete tmp;
}
return value;
}
现在,由于第一个答案,我最初是这样编写 pop 函数的:
// Pop the top element off of the stack and return its value.
StackElement Stack::Pop()
{
assert (!Empty());
StackElement poppedData = tos->data;
Node *temp = new Node;
temp = tos;
tos = tos->next;
delete temp;
return poppedData;
}
但是,我的老师说创建一个新节点来删除以前的节点会导致内存泄漏。
最终我重写了我的代码以匹配样式二,如下所示:
StackElement Stack::Pop()
{
assert (!Empty());
StackElement poppedData = tos->data;
Node *temp = tos;
tos = tos->next;
delete temp;
return poppedData;
}
谁能向我解释为什么第一个实现是错误的?当该人将其发布在另一个 stackoverflow 问题上时,我很惊讶没有人对此发表评论。在我看来,我正在创建一个指向新节点(又名新内存地址)的 Node 类型的指针 temp,然后我将该内存地址的值设置为堆栈内存顶部的值地址。我将栈顶移动到下一个节点,然后删除我创建的这个临时节点,但是因为我将它声明为一个新节点,它只具有旧栈顶的值,它实际上与那个节点。旧的栈顶节点已从栈中移除,但内存未正确释放。这是正确的吗?
【问题讨论】:
-
是的,看起来您找到的第一个答案泄漏了为
tmp分配的内存。我建议对它发表评论,以便向任何可能找到它的人指出。 -
第一个答案太错误了,甚至都不好笑。我投了反对票,你也应该这样做。
-
我刚刚投了反对票。我发现它之前没有得到任何反对意见令人不安。
-
顺便说一句。在纸上画出你的堆栈。链接的数据结构可以很好地可视化,然后很容易看到会发生什么。
-
错误不仅因为无故内存泄漏,而且(更重要的是)因为复杂性错误。您不应该遍历整个堆栈来推送或弹出元素。
标签: c++ stack new-operator singly-linked-list delete-operator