代码之家  ›  专栏  ›  技术社区  ›  jkeys

是否可以使用“删除此”删除当前对象?

  •  7
  • jkeys  · 技术社区  · 15 年前

    我正在写一个链表,我希望一个结构的析构函数(一个节点结构)能够简单地删除它自己,并且没有任何副作用。我希望列表的析构函数在自身上迭代调用节点析构函数(临时存储下一个节点),如下所示:

    //my list class has first and last pointers
    //and my nodes each have a pointer to the previous and next
    //node
    DoublyLinkedList::~DoublyLinkedList
    {
        Node *temp = first();
    
        while (temp->next() != NULL)
        {
            delete temp;
            temp = temp->next();
        }
    }
    

    这就是我的节点析构函数:

    Node::~Node
    {
       delete this;
    }
    

    这是否可以接受,特别是在这种情况下?

    8 回复  |  直到 12 年前
        1
  •  17
  •   Brian R. Bondy    15 年前

    如果正在调用节点析构函数,则它已经处于删除过程中。因此,删除在节点析构函数中没有意义。

    while (temp->next() != NULL)
    {
         delete temp;
         temp = temp->next();
    }
    

    相反,您应该获得temp->将next()转换为临时变量。否则,您将访问已删除的内存。

    更像这样:

    DoublyLinkedList::~DoublyLinkedList
    {
      Node *temp = first();
      while (temp != NULL)
      {
           Node *temp2 = temp->next();
           delete temp;
           temp = temp2;
      }
    }
    
        2
  •  4
  •   Scott Stanchfield    15 年前

    不,你不应该 delete this

        3
  •  4
  •   Dmitry Brant    15 年前

    目前,您的代码会导致访问冲突,因为以下第二行显然会访问已释放的内存:

    delete temp;
    temp = temp->next();
    

    DoublyLinkedList::~DoublyLinkedList
    {
        Node *temp = first();
        delete temp;
    }
    
    Node::~Node
    {
       if(this->next() != NULL) delete this->next();
    }
    
        4
  •  2
  •   sbi    15 年前

    在做其他事情之前:我真的,真的希望这是分配给你们的家庭作业,以便理解一个双链表。否则,就没有理由用它来代替 std::list . 有了这条路:

    delete this 在dtor中总是错误的,因为当 this 处于被删除的状态。

    delete temp;
    temp = temp->next();
    

    temp->next() , temp 非常 你身上有讨厌的鼻魔。)

    请注意,可以通过删除节点的dtor中的下一个节点来解决这两个问题:

    Node::~Node()
    {
       delete next();
    }
    

    这样,您的列表dtor也变得非常简单:

    DoublyLinkedList::~DoublyLinkedList()
    {
        delete first();
    }
    

    对我来说,这似乎是DTR发明的目的,所以,除了现在没有人应该再编写自己的链表类型之外,对我来说这似乎是 C++解决方案 解决你的问题。

        5
  •  1
  •   Jagannath    15 年前

        6
  •  0
  •   Jinuk Kim    15 年前

    上面的代码将调用Node::~Node()两次。(在“删除临时”和节点::~Node()中)

    Node::~Node()不应调用“delete this”(否则程序将崩溃)

    另外,代码中的while循环将不起作用。它将取消对无效指针的引用。

        7
  •  0
  •   Platinum Azure    15 年前

    一般来说,析构函数应该只考虑删除(或释放,如果使用C或malloc)专门为对象分配的任何内存。删除指向对象的指针将始终由操作系统管理,您不必担心该部分的任何问题。

    值得记住的一点是,在构造时,首先创建对象(当控制流进入构造函数的主体时),然后再创建其中的对象;对于销毁,您必须反向执行,因为如果您首先删除外部对象,您将无法访问内部指针来删除这些对象。相反,您可以使用析构函数删除内部对象,然后当控制流脱离析构函数时,操作系统管理内存的实际释放。

    顺便说一句,子类化也会发生同样的事情——如果你有类A,类B:public A,那么当你做一个新的B()时,A构造函数首先执行,然后是B的构造函数;销毁时,先执行B的析构函数,然后执行A的析构函数。我很确定,你不必担心这一点,不过C++会帮你处理这个问题。因此,不要试图找出一种方法来调用超类上的delete。

        8
  •  0
  •   sharptooth    15 年前

    DoublyLinkedList::~DoublyLinkedList
    {
        Node *temp = first();
        while (temp->next() != NULL)
        {
            delete temp;
            temp = temp->next();
        }
    }
    

    将导致未定义的行为-不允许访问已返回堆的内存。相反,它应该是:

    DoublyLinkedList::~DoublyLinkedList
    {
        Node *temp = first();
        while( temp != NULL)
        {
            Node* next = temp->next();
            delete temp;
            temp = next;
        }
    }
    

    delete this 将导致所谓的双重自由,这也将导致未定义的行为。析构函数应该只为指针成员变量调用delete,而不为指针成员变量调用delete this . 使命感 删除这个 从其他方法取消分配当前对象是合理的,但从析构函数取消分配是不合理的。