1

我在删除指针时遇到问题。我不认为我在做任何编译器非法或任何事情,但也许我是,所以如果有人能解释我的逻辑中的缺陷,我将不胜感激。我希望下面的函数应该足以提供帮助,因为整件事要转录很多,但是如果需要更多代码,请告诉我,我会添加它!

以下是从我创建的链接列表中删除储物柜的功能。我已尽力涵盖所有可能的情况。当我尝试实际释放要删除的储物柜的内存时,就会出现问题。我试图删除引用锁定的临时变量的行被注释掉了,因为包含它们的代码中断了。很明显,不过,没有它们,我不能像我想要的那样删除储物柜。

int SelfStorageList::removeLockersOverdue() {

int lockersDeleted = 0;

if (isEmpty()) {
    return 0;
}

if (head->objLocker.isRentOverdue && head==tail) { //If that was the only locker, the tail needs to be updated to = head = 0
    delete head;  
    head = tail = 0;
    return ++lockersDeleted;
}

LockerNode *prev = head;
LockerNode *curr = head->next;

while (curr != 0) {

    if((curr == tail) && curr->objLocker.isRentOverdue) { //If the current locker is tail and needs deleting
        LockerNode *temp = curr;
        curr = prev;
        //delete temp;
        lockersDeleted++;
    }


    if(prev->objLocker.isRentOverdue) { //General case: Previous locker needs deleting
       LockerNode *temp = prev;
       prev = prev->next;
       curr = curr->next;
       //delete temp;
       lockersDeleted++;

   }

  else { //Update the pointers if not updated anywhere else

  prev = prev->next; 
  curr = curr->next;

  }

}

return lockersDeleted;

}

任何“指针”?(可怕的双关语。:p)

4

2 回答 2

3

prev因为您正在维护一个单链表,所以我看到您在遍历列表时正在跟踪指针。当然,这是应该的,因为如果它是单链接的,则无法在链表中获取给定节点的前一个节点,而不记得它的前一个节点是什么。您的问题只是您的逻辑被破坏了:如果需要删除,您需要删除curr节点,并修补prev节点以将其next指针指向您curr->next之前的delete curr.

想一想:您正在做的是删除prev节点,但可能有一个“比该节点更早”的节点仍然指向prev您刚刚删除的节点。下一次遍历列表时,您将迭代到以前分配的节点,届时可能会为某些完全不同的目的而分配这些节点。您的内存分配器未能通过一些内部断言,因为可能在您下次调用 removeLockersOverdue() 时,内存尚未分配给其他东西,并且您仍然在那里找到已删除的相同节点,并再次发现它过期了,然后再次删除它,并且您的内存分配器抱怨您正在删除未分配的内存。

此外,您处理第一个节点和最后一个节点的特殊情况可以简化和通用;我会避免为你重写它,所以你可以看看你是否可以自己简化它。

于 2013-06-14T01:03:30.817 回答
3
while (curr != 0) {
    if((curr == tail) && curr->objLocker.isRentOverdue) {
        LockerNode *temp = curr;
        curr = prev;
        //delete temp;
        lockersDeleted++;
    }

您没有在此处更新前一个节点的下一个指针,因此它最终会悬空(指向已删除的内存)。您还tail指向已删除的节点。

    if(prev->objLocker.isRentOverdue) {
       LockerNode *temp = prev;
       prev = prev->next;
       curr = curr->next;
       //delete temp;
       lockersDeleted++;

   }

同样,您不会更新next列表中指向已删除节点的指针。

  else { //Update the pointers if not updated anywhere else

  prev = prev->next; 
  curr = curr->next;

  }
}

我认为通过在循环中携带两个指针,您会感到非常困惑。尝试用一个跟踪您当前正在检查的节点的指针再次编写它,并绘制三种可能情况(删除第一个节点、删除最后一个节点、删除内部节点)的一些图片,以确保您获得正确的删除逻辑。

于 2013-06-14T01:03:53.637 回答