2013-10-19 76 views
0

我正在爲我的C++類開發一個檢查器的模擬遊戲。我的問題在於保存跳棋的鏈接列表。除了列表頭之外,我可以完全刪除任何檢查器。我查看過這裏和其他網站,我相信有某處存在內存泄漏。我對C++相當陌生,所以除了玩弄事物(這可能只會造成更大的問題)之外,我不確定要做些什麼。我從來沒有在這裏發佈過,所以如果格式稍微偏離或太雜亂,請原諒我。我會盡量簡短。首先,這是鏈表的節點類的一個片段。試圖刪除頭時有意刪除整個鏈表

class CheckerpieceNode 
{ 
private: 
    Checkerpiece *Node; 
    CheckerpieceNode *Next; 
public: 
    CheckerpieceNode(); // sets Node and Next to NULL in .cpp file 
    void setNode(Checkerpiece *node); 
    void setNext(CheckerpieceNode *next); 
    Checkerpiece* getNode(); 
    CheckerpieceNode* getNext(); 
}; 

這些函數的設置與您在Checkerpiece.cpp類中所期望的幾乎相同。 以下是代碼的使用方法。它由我的主類中的Checkerboard對象調用。

theCheckerboard.removeChecker(theCheckerboard.findChecker(selector->getCurrentX() + 0, selector->getCurrentY() - VERTICAL_SHIFT, listHead), listHead); 

VERTICAL_SHIFT只是我的棋盤圖形在控制檯上的方式。由於它適用於所有其他節點(不包括頭部),所以我排除它作爲錯誤的來源。選擇器是棋子對象,但它不是列表的一部分。

以下是Checkerboard類中的實際findChecker和removeChecker代碼。

Checkerpiece* findChecker(int x, int y, CheckerpieceNode* list_head) 
{ 
if(list_head== NULL) return NULL; // do nothing 
else 
{ 
    CheckerpieceNode* node = new CheckerpieceNode; 
    node = list_head; 
    while(node != NULL && node->getNode() != NULL) 
    { 
     if()// comparison check here, but removed for space 
     { 
      return node->getNode(); 
      delete node; 
      node = NULL; 
     } 
     else // traversing 
      node = node->getNext(); 
    } 

    return NULL; 
} 
} 


void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* list_head) 
{ 
if(list_head== NULL) // throw exception 
else 
{ 
    CheckerpieceNode *temp = NULL, *previous = NULL; 
    Checkerpiece* c_checker= new Checkerpiece; 
    temp = list_head; 
    while(temp != NULL && temp->getNode() != NULL) 
    { 
     c_checker= temp->getNode(); 
     if(d_checker!= c_checker) 
     { 
      previous = temp; 
      temp = temp->getNext(); 
     } 
     else 
     { 
      if(temp != list_head) 
      { 
       previous->setNext(temp->getNext()); 
       delete temp; 
       temp = NULL; 
      } 
      else if(temp == list_head) // this is where head should get deleted 
      { 
       temp = list_head; 
       list_head= list_head->getNext(); 
       delete temp; 
       temp = NULL; 
      } 


      return; 
     } 
    } 
} 
} 

回答

0

噢,我的,你是複雜的。大量冗餘檢查,分配和不必要的變量(如c_checker也會泄漏內存)。

// Write down the various scenarios you can expect first: 
// (a) null inputs 
// (b) can't find d_checker 
// (c) d_checker is in head 
// (d) d_checker is elsewhere in the list 
void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* list_head) { 
    // first sanitize your inputs 
    if (d_checker == nullptr || list_head == nullptr) // use nullptr instead of NULL. its a keyword literal of type nullptr_t 
     throw exception; 

    // You understand that there is a special case for deleting head. Good. 
    // Just take care of it once and for all so that you don't check every time in the loop. 
    CheckerpieceNode *curr = list_head; 

    // take care of deleting head before traversal 
    if (d_checker == curr->getNode()) { 
     list_head = list_head->next; // update list head 
     delete curr; // delete previous head 
     return; // we're done 
    } 

    CheckerpieceNode *prev = curr; 
    curr = curr->next; 

    // traverse through the list - keep track of previous 
    while (curr != nullptr) { 
     if (d_checker == curr->getNode()) { 
      prev->next = curr->next; 
      delete curr; 
      break; // we're done! 
     } 

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

我希望有幫助。花時間將問題分解成更小的部分,找出可能的情況,如何處理它們,然後纔開始編寫代碼。

+0

感謝您的回覆。我現在只是在C/C++中學習堆內存,所以我有一種感覺,那就是我搞亂了一些東西。只是澄清,每當我想垃圾收集,我只使用C++中的刪除(在C中免費)?但僅用於堆內存,不是堆棧或靜態? – Zach

+0

是。如果你想讓你的生活更輕鬆,你可以使用shared_ptr 和#include 。您甚至不需要刪除 - shared_ptr對象將引用計數並確保刪除。它是一個很好的練習,可以編寫代碼,在那裏你可以通過刪除來理解堆分配的概念。 代碼中的一個錯誤是當你想要做的只是使用一個指向節點的附加指針時分配內存。 – Raja

0

removeChecker不能修改list_head的值,因爲它是按值過去的。該方法的簽名應該是:

void removeChecker(Checkerpiece* d_checker, CheckerpieceNode** list_head) 
// You will need to call this function with &list_head 

void removeChecker(Checkerpiece* d_checker, CheckerpieceNode* &list_head) 
// Calling code does not need to change 
0

基於this edit對這個問題筆者,他所使用的解決方案是:

我修改了代碼,以顯示傳入檢查地址刪除 功能。

void delete_checker(Checker* d_checker, CheckerNode* &list_head) // pass by address 
{ 
if(list_head== NULL) // throw exception 
else 
{ 
    CheckerNode*temp = NULL, *previous = NULL; 
    Checker* c_checker= new Checker; 
    temp = list_head; 
    while(temp != NULL && temp->node!= NULL) 
    { 
     c_checker= temp->node; 
     if(d_checker!= c_checker) 
     { 
      previous = temp; 
      temp = temp->next; 
     } 
     else 
     { 
      if(temp != list_head) 
      { 
       previous->next = temp->next; 
       delete temp; 
       temp = NULL; 
      } 
      else if(temp == list_head) // this is where head should get deleted 
      {  
       temp = list_head; 
       list_head= list_head->next; 
       delete temp; 
       temp = NULL; 
      } 

        delete c_checker; 
        c_checker = nullptr; 

      return; 
     } 
    } 
} 
}