首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >析构函数中的“中途”删除并尝试移除其他对象中的引用

析构函数中的“中途”删除并尝试移除其他对象中的引用
EN

Stack Overflow用户
提问于 2016-03-14 04:00:06
回答 2查看 47关注 0票数 0

我有一个树结构,其中每个节点都包含一个指向其父对象的指针和一个子对象的向量。我的意图是,当一个节点被删除时,它会删除它的子节点,然后再删除它们的子节点,依此类推。

代码语言:javascript
复制
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];
    }
}

我也想让它从子节点的父向量中删除自己,但在尝试调试时(它导致了一个双重释放错误),我在析构函数中发现了一些我无法解释的行为,包括不同的“数量”删除。

我用来测试它的代码如下:

代码语言:javascript
复制
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";
}

当我运行它的时候,我得到的并不是我所期望的,我不能完全解释它:

代码语言:javascript
复制
Children of root:
ID No. 1
ID No. 2
Children of leaf:
ID No. 3

这一切都在预料之中。

代码语言:javascript
复制
Deleting leaf
Deleting 1
Deleting 3
Children of root:
ID No. 28168496
ID No. 2

好的,这只是看看释放的内存

代码语言:javascript
复制
ID of leaf: 28168496
ID of leaf3: 0

所以,很明显,leaf3没有像leaf那样被删除。它的字段已经被更改了,即使在children向量之外访问时也是如此,但是我认为内存并没有被释放?更重要的是,如果我将另一个delete leaf3附加到程序中,它会毫不费力地这样做,导致它的行为像leaf一样,但如果我在delete leaf中添加,它就会陷入无限循环。这种行为是一致的,而且始终是相同的:查找leaf的ID将返回数字,但leaf3总是返回0。

这里发生了什么,我应该如何正确地删除节点的子节点?这是否与我从向量中删除数据的问题有关?

EN

回答 2

Stack Overflow用户

发布于 2016-03-14 04:19:32

代码看起来是正确的。只要您删除了指针,它所指向的对象就会被销毁,并且内存已可供重用。删除无效指针后,不要到处查看无效指针所指向的内存;那里没有任何有意义的东西。内存管理器可能对内容做了某些操作,也可能没有。

票数 0
EN

Stack Overflow用户

发布于 2016-03-14 04:57:26

在你的代码中,你可以这样写:

代码语言:javascript
复制
delete leaf;
leaf->getID();

这会导致undefined behaviour。在删除leaf所指向的对象后,您将无法使用该对象。您也不能使用leaf3

另一个问题是你会写:

代码语言:javascript
复制
delete leaf;

这会使root的子级列表中包含一个悬空指针。在删除之前,您需要从root的列表中删除此指针。

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

您没有显示足够的代码来指示一个间隔是否还包含指向其父对象的指针。如果是这样的话,您可以修改隔间的析构函数,以便在删除它时将其自身从其父对象中移除。

否则,您将需要找到其他方法在删除指针之前将其从结构中移除。

我追加了另一个删除leaf3

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

考虑让你的隔间包含智能指针而不是原始指针,这样你就不用担心这些了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35975095

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档