2016-03-13 31 views
0

我有一個樹結構,其中每個節點都包含一個指向其父對象及其子對象向量的指針。我的本意是,當一個節點被刪除,但刪除其子女,這反過來又刪除自己的孩子,等在析構函數中刪除「中途房屋」並嘗試刪除其他對象中的引用

Compartment::Compartment(int inpID, eType inpEnum, double inpX, double inpY, double inpZ, double inpR, Compartment* inpParent){ 
    ID = inpID; 
    ... 
    parent = inpParent; 
    std::vector<Compartment*> v; 
    children = v; 
    if (parent != nullptr){ 
     parent->children.push_back(this) //Is this poor coding? 
    } 
} 

Compartment::~Compartment(){ 
     /*int pos; 
     for (int ii = 0; ii < getParent()->getChildren().size; ii++){ 
      if (getParent()->getChildren()[ii]->getID() == ID){ 
       pos = ii; 
       getParent()->getChildren().erase(getParent->getChildren().begin()+pos); 
      } 
     }*/ //Un-commenting this gives a double-free error 
    std::cout << "Deleting " << ID << "\n"; 
    for (int ii = 0; ii < children.size(); ii++){ 
     delete children[ii]; 
    } 
} 

我也希望得到它從子節點其父母載體自身刪除,但在試圖調試(它導致了一個雙免費錯誤)我發現了一些我無法解釋的析構函數中的行爲,包括不同的「刪除量」。

我用來測試這個代碼是在這裏:

int main(){       //ID type co-ordinates parent 
    Compartment *root = new Compartment(0,ENUM_A,0.0,0.0,0.0,1.0,nullptr); 
    Compartment *leaf = new Compartment(1,ENUM_A,1.0,2.0,2.0,1.0,root); 
    Compartment *leaf2 = new Compartment(2,ENUM_A,1.0,2.0,2.0,1.0,root); 
    Compartment *leaf3 = new Compartment(3,ENUM_A,1.0,2.0,2.0,1.0,leaf); 
    std::cout << "Children of root:\n"; 
    std::vector<Compartment*> kids = root->getChildren(); 
    for (int ii = 0; ii < kids.size(); ii++){ 
     std::cout << "ID No. " << kids[ii]->getID() << "\n"; 
    } 
    std::cout << "Children of leaf:\n"; 
    kids = leaf->getChildren(); 
    for (int ii = 0; ii < kids.size(); ii++){ 
     std::cout << "ID No. " << kids[ii]->getID() << "\n"; 
    } 
    std::cout << "Deleting leaf\n"; 
    delete leaf; 
    std::cout << "Children of root:\n"; 
    kids = root->getChildren(); 
    for (int ii = 0; ii < kids.size(); ii++){ 
     std::cout << "ID No. " << kids[ii]->getID() << "\n"; 
    } 
    std::cout << "ID of leaf: " << leaf->getID() << "\n"; 
    std::cout << "ID of leaf3: " << leaf3->getID() << "\n"; 
} 

我能得到什麼,當我跑這不是我所期望的,我不能完全解釋:

Children of root: 
ID No. 1 
ID No. 2 
Children of leaf: 
ID No. 3 

這一切都如預期。

Deleting leaf 
Deleting 1 
Deleting 3 
Children of root: 
ID No. 28168496 
ID No. 2 

OK,所以這只是在尋找釋放的內存

ID of leaf: 28168496 
ID of leaf3: 0 

因此,很明顯leaf3尚未被以同樣的方式刪除,leaf。它的字段已被更改,即使在訪問children矢量之外時,但我認爲內存還沒有被釋放?更重要的是,如果我在程序中附加了另一個delete leaf3,它沒有任何問題,因此它的行爲類似於leaf,但是如果我將其添加到delete leaf中,它會陷入無限循環。這種行爲是一致的,總是一樣的:找到leaf的ID返回的數字,但leaf3總是產生0.

這裏發生了什麼,我該如何正確地去刪除節點的子節點?這與我的問題有關,從矢量中刪除數據?

回答

0

代碼看起來正確。只要你刪除指針,它指向的對象就被銷燬了,並且內存已經可以重用了。不要在leaf3被無效指針指向的內存被刪除後,那裏沒有什麼意義。內存管理器可能對內容做了些什麼,或者可能沒有。

0

在你的代碼寫:

delete leaf; 
leaf->getID(); 

這將導致undefined behaviour。刪除指向的對象後,不能使用leaf。你也不能使用leaf3

另一個問題是,你寫的:

delete leaf; 

留下含懸擺指針兒童root的名單。在刪除它之前,您需要從root的列表中刪除此指針。

你可以在你的程序輸出中看到一些證據:你得到一個垃圾值作爲第一個孩子的ID。這實際上是未定義的行爲,任何事情都可能發生。

您沒有顯示足夠的代碼來指示隔離專區是否也包含指向其父代的指針。如果是這樣,您可以修改分區的析構函數,以在其被刪除時從其父項中移除。

否則,在刪除結構之前,您需要找到一些其他方法來從結構中刪除指針。

我追加另一刪除leaf3

刪除同一內存的兩倍還導致不確定的行爲。

考慮讓你的隔間包含智能指針而不是原始指針,那麼你不必擔心任何這些。

+0

>刪除相同的內存兩次也會導致未定義的行爲 對不起,我應該指定我的意思是它不會導致雙精度錯誤。 – Nihilingix