对象删除时双重免费或损坏错误

时间:2017-09-18 12:39:34

标签: c++ memory-management data-structures

我试图通过实现一个简单的链表类来学习C ++。在这个类中有一个函数,我从链接列表中删除一个节点,并尝试从内存中删除该对象。

void List::deleteNode(Node *n, Node **h){

    Node **dp = h;

    while(*dp && (*dp)->getValue().compare(n->getValue())!=0){
       dp = &(*dp)->next; 
    }
    if(*dp == NULL){
        return;
    }

    Node *temp = *dp;

    *dp = (*dp)->next;

    delete temp;
}

列表中的删除部分有效。但是当调用delete temp时,我收到内存错误:

*** Error in `./node.exe': double free or corruption (out): 0x00007fff450d29b0 ***

这是在C ++中清除内存的正确方法吗?我应该如何清除物体?或者在这种情况下是否需要这样的操作?

3 个答案:

答案 0 :(得分:1)

  

或者在这种情况下是否需要这样的操作?

因为我假设您已使用new创建了要删除的节点。

  

这是在c ++中清除内存的正确方法吗?

嗯,每执行一次delete都应该执行一个new

然而,真正的问题是 - 我这样做吗?显然不是!

想象一下有3个节点的单个列表。您想要删除中间的那个(最简单的情况)。现在,您使用*dp*dp = (*dp)->next;指向要删除的节点中的下一个节点。

但是前一个节点怎么样?这不会打破你的列表并创建一个悬空指针吗?

我的意思是前一个节点仍然指向要删除的节点!

因此,在循环中,跟踪上一个点(在您要删除的点之前),并使前一个节点指向*dp的下一个节点。

然后安全删除temp

当然,您需要了解极端情况(例如,当要删除的节点是列表的第一个节点时(在这种情况下没有上一个节点))。

  

我没有使用new

那么你不应该delete。这就是程序崩溃的原因。

答案 1 :(得分:0)

您的代码会删除内存,是的。同时,链表仍然没有变化。您必须修改“previous-> next”才能跳过已删除的元素以供进一步使用。像这样:

(*previous)->next = (*dp)->next;
delete dp;

答案 2 :(得分:0)

我在你的代码中看到的一件事是你试图缩短事情然后混淆。一个接一个地做,并在需要时使用冗余。

首先,你的参数是什么?我看过nh。这是两个任意字母。有时候,人们很容易猜到简单的名字是什么意思,就像你有Rectangle(double a, double b)之类的东西一样。但在这种情况下呢?不。我不知道乍一看h应该是什么。我可以认为它是头节点,但为什么我们需要它?无论如何,我们将在头节点或外包装上调用它。你在List上调用它,它看起来像一个应该已经有头节点的外包装器。此外,您在删除中输入节点,但该方法不会删除该节点,而是删除具有相同数据值的节点。如果要执行此操作,请将值作为输入。也许首先编写关于如何创建和调用类的对象的示例代码,并从中派生出您的方法。

而不是所有这些,使用名称。像输入Node* to_delete

下一步是提取您需要的一切。慷慨地开始,即使您以后不需要,也可以获得您认为可能所需的一切。您可以稍后删除它。例如,获取三个节点previousto_deletenext。拿出他们的指针并清楚地命名,如previous_next_old。例如,这一点与to_delete相同,所以你可能会认为它已经过时,但如果你感到困惑,那么最好过时而不是混乱。同样,我们可以稍后改变它。

然后创建像previous_next_new这样的指针并相应地设置它们,可能基于绘图(如molbdnilo的答案)。只有这样你才开始删除过时的变量。如果有疑问,你仍然会让他们有很长的描述性名字。如果您这样做,则可以使用delete to_delete;结束代码,而无需再考虑。

另一件事,你不需要双指针。您可以做的只是常规的。如果nextNode*,那么就这样(使用Node* current

while(current != nullptr && current->value != target_value){
    current = current.next;
}

(另请注意,我具体说明它不是nullptr - 你的代码使用它作为布尔值就好了,不是说你应该把它改成我是怎么做的,但是我想强调它是的也可以暂时把这些东西写出来。在精致的产品中,我会像你那样做,但在那之前,让我们详细说明。)

现在,如果你愿意,我可以为你提供一个完整的架构,但我认为你想要自己尝试(无论如何更好)。无论如何,当你的代码工作得很好时,我建议你在CodeReview上发帖。

编辑:您可能想要考虑的另一件事是这种架构:

class Node {
    //double value; << or T value or whatever
    shared_ptr<Node> next;
    //weak_ptr<Node> previous; << if double linked
}

此架构不需要手动删除,只需更改指针。在这种结构中,如果没有任何点指向节点,则节点由于智能指针所有权的性质而死亡。只有一个节点环可以在活动变量的引用之外存活,并且环很容易避免。但我认为你做的是更好的锻炼。