"中途宿舍"在析构函数中删除并尝试删除其他对象中的引用

时间:2016-03-13 20:00:06

标签: c++ object dynamic destructor

我有一个树结构,其中每个节点都包含一个指向其父对象的指针和一个子对象的向量。我的意图是当一个节点被删除时,它会删除它的子节点,从而删除它们的子节点等等。

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];
    }
}

我还想让它从父节点的子节点向量中删除自己,但是在尝试调试时(它导致双重自由错误)我在析构函数中发现了一些我无法解释的行为,包括不同的&#34;金额&#34;删除。

我用来测试它的代码在这里:

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

好的,所以这只是看着释放的内存

ID of leaf: 28168496
ID of leaf3: 0

所以,显然leaf3的删除方式与leaf相同。它的字段已被更改,即使在children向量之外访问,但我认为内存尚未被释放?更重要的是,如果我将另一个delete leaf3附加到该程序,它会毫无问题地执行,导致它的行为类似leaf,但如果我添加delete leaf它卡在一个无限循环中。这种行为是一致的,并且总是以相同的方式:找到leaf的ID返回数字,但leaf3总是得到0。

这里发生了什么,以及如何正确删除节点的子节点?这与我从向量中删除数据的问题有关吗?

2 个答案:

答案 0 :(得分:0)

代码看起来正确。只要删除指针,它指向的对象就会被销毁,内存可以重用。不要删除被删除后的无效指针(如public void onCheckboxClicked(View view) { boolean checked = ((CheckBox) view).isChecked(); switch(view.getId()){ case R.id.concern: if(checked) { score += 1; } break; case R.id.faith: if(checked){ score+=1; } break; case R.id.respect: if(checked){ score+=1; } break; case R.id.education: if(checked){ score+=1; } break; case R.id.community: if(checked){ score+=1; } break; } // adds the variables together to form a score //} <-- REMOVE THIS CURLY BRACKET if(score == 0){ output.setText("Come on! Get involved, your la sallian community needs you."); } else if( score == 1){ output.setText("Good start, keep going!"); } else if( score == 2){ output.setText("Room to improve but doing good!"); } else if(score == 3){ output.setText("Very good, others look up to you!"); } else if(score == 4){ output.setText("Wow, you really are an inspiration"); } else if(score == 5){ output.setText("Excellent! You're a leader in your la sallian community"); } else{ output.setText("Unknown"); } // changes the output text based on score value } // <-- MOVE THE CURLY BRACKET HERE )指向的内存;那里没什么意义。内存管理器可能已经对内容做了一些事情,或者它可能没有。

答案 1 :(得分:0)

在你的代码中写道:

delete leaf;
leaf->getID();

这导致undefined behaviour。删除它指向的对象后,不能使用leaf。你也不能使用leaf3

另一个问题是你写道:

delete leaf;

留下root的包含悬空指针的子项列表。在删除之前,您需要从root列表中删除此指针。

您可以在程序输出中看到这方面的一些证据:您将垃圾值作为第一个孩子的ID。这实际上是未定义的行为,任何事情都可能发生。

您没有显示足够的代码来指示隔离专区是否还包含指向其父级的指针。如果是这样,您可以修改Compartment的析构函数,以便在删除它时将其自身从父项中删除。

否则,在删除之前,您需要找到一些从结构中删除指针的方法。

  

我追加另一个删除leaf3

两次删除相同的内存也会导致未定义的行为。

考虑让你的隔间包含智能指针而不是原始指针,然后你不必担心这些。