在链表中删除该节点时,Node* 接下来会发生啥?

Posted

技术标签:

【中文标题】在链表中删除该节点时,Node* 接下来会发生啥?【英文标题】:What happens to Node* next when deleting that Node in a linked list?在链表中删除该节点时,Node* 接下来会发生什么? 【发布时间】:2019-04-09 10:21:52 【问题描述】:

在使用

的链表中
struct Node 
  T value;
  Node* next; 

对于每个使用的 new 运算符(new Node()),必须有一个 delete 运算符。 此类列表的析构函数示例

~LinkedList() 
   Node* tmp = head;
   while(tmp! = nullptr)
     delete tmp;
     tmp = tmp->next;
   
 

我的问题是,究竟是什么被“删除”,让我可以使用 next 指针 即使在使用 delete 之后?它只删除值吗?它在记忆中的实际表现如何?

【问题讨论】:

delete 伴随着一个动作。链表中前一个元素的下一个元素现在指向被删除元素之后的元素。 您的代码有错误。如果你打电话给delete tmp 然后在 tmp->next 你会得到访问冲突或类似的东西 tmp->next after delete tmp 可能有时会起作用,但这是严格未定义的行为。 @MichaelChourdakis 不在此代码中。 @MichaelChourdakis delete伴随着移动,你的其余评论都不会出现在这段代码中。你在说什么? 【参考方案1】:

在 C++ 中,当您删除堆上的对象时,实际上并没有清理任何东西,它只是将内存标记为“空闲”。这意味着再次调用 newmalloc 可能会覆盖该内存。

访问已删除的指针是未定义的行为,因为它们不能保证驻留在那里的数据。我不太精通操作系统如何处理内存,但我相信如果这是您从该部分内存中删除的最后一项,您的程序甚至可能不再拥有该页面。如果发生这种情况,那么取消引用该指针将导致大多数桌面操作系统出现分段错误。

如果您想安全地移动头部,您应该在指针处于活动状态时为下一项分配一个临时值,然后您可以从内存中删除底层对象。

【讨论】:

【参考方案2】:

删除数据后,指针变为未定义,并且肯定不会到达之前指向的内存,因此删除后无法调用tmp=tmp->next'

正确的析构函数声明应该是:

~LinkedList()

    while (head != nullptr)
    
        Node * tmp = head->next;
        delete head;
        head = tmp;
    

顺便说一句:请阅读一些关于如何实现列表的好书。

BTW.2:如果您确实需要,请使用一些标准容器,例如 vectorlist

【讨论】:

C++ 在取消引用指针之前不会进行内存边界检查或验证。如果它们之前是有效的内存,只要应用程序仍然拥有该内存页,就可以取消引用它。当该位置的数据不再代表有效对象(已被覆盖)时,由于任何内部指针现在是完全不同的数据,导致在原始对象之外的内存上发生读取/写入,您很可能会遇到错误. 指针没有“变得未定义”;并且肯定它指向它之前指向的相同内存。问题是这个内存现在被释放了,所以它可能随时被覆盖,甚至映射出用户的地址空间。 OP 的代码可能大部分时间都可以工作。

以上是关于在链表中删除该节点时,Node* 接下来会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何指向链表中的下一个节点并打印该值

链表----在链表中添加元素详解--使用链表的虚拟头结点

LeetCode 237. Delete Node in a Linked List (在链表中删除一个点)

在链表中添加节点时使用双指针的原因是啥?

剑指Offer之在O时间删除链表节点

如何在链表中的另一个节点之间插入一个节点?