DAG析构函数出错

时间:2015-06-05 12:13:52

标签: c++ destructor directed-acyclic-graphs

我有一个Dag类(Directed Acyclic Graph),它包含一个指向Node类对象的原始指针向量。此向量称为m_roots,由所有没有后代的节点组成。 (但它们最多可以有两个父节点)Node对象形成各种二叉树。 节点的成员属性是:

int m_indiv;
Node * m_dad;
Node * m_mom;
std::vector<Node * > m_offsprings;
int m_generat;

因此虽然结构是非循环的,但我在两个方向都有指针。 Dag构造函数启动一个重复,它根据地图中包含的数据创建节点。这是经常性的部分:

void Node::recNode(const map<int, pair<int, int> > &mapPed, map<int, Node * > &mapDup, const vector <int> &sampleListe, vector<Node * > &sample)
{

    if (find (sampleListe.begin(), sampleListe.end(), this->m_indiv) != sampleListe.end()) {
        sample.push_back(this);
    }
    pair<int, int> parents;


    if (parents.first!=0) { //0 is a reserved integer for missing data, pointer stay to NULL (nullptr)
        if (mapDup.find(parents.first) == mapDup.end() || !(mapDup[parents.first])) {
            m_dad=new Node(parents.first);
            if (mapDup.find(parents.first) != mapDup.end()) { 
                mapDup[parents.first]=m_dad;
            }
            m_dad->recNode(mapPed, mapDup, sampleListe, sample);
        }
        else {
            m_dad=mapDup[parents.first];
        }
        m_dad->m_offsprings.push_back(this); //add the pointer to this node in the dads list of offspring
    }

    //do the same for the second parent
    if (parents.second!=0) {
        if (mapDup.find(parents.second) == mapDup.end() || !(mapDup[parents.second]) ) {
            m_mom=new Node(parents.second);
            if (mapDup.find(parents.second) != mapDup.end()) {
                mapDup[parents.second]=m_mom;
            }
        m_mom->recNode(mapPed, mapDup, sampleListe, sample);
        }
        else {
            m_mom=mapDup[parents.second];
        }
        m_mom->m_offsprings.push_back(this); //add the pointer to this node in the moms list of offspring
    }

}

我的Dag析构函数启动递归破坏:

Dag::~Dag()
{
    for (int i(0); i<m_roots.size();++i) {
        delete m_roots[i];
    }
}

Node析构函数应该进行实际的破坏:

Node::~Node()        

{
    if(m_dad) {
        Node* dummyD=m_dad;
        for (int i(0); i<m_dad->m_offsprings.size();++i) {
            if (m_dad->m_offsprings[i]) {
                m_dad->m_offsprings[i]->m_dad=nullptr;
            }
        }
        delete dummyD;
    }
    if(m_mom) {
        Node* dummyM=m_mom;
        for (int i(0); i<m_mom->m_offsprings.size();++i) {
            if (m_mom->m_offsprings[i]) {
                m_mom->m_offsprings[i]->m_mom=nullptr;
            }
        }
        delete dummyM;
    }

}

由于某些原因,这不起作用:我遇到了Seg Fault。 相应的Valgrind错误是:

InvalidRead                                     Invalid read of size 8
                                                Call stack:
/usr/include/c++/4.8/bits/stl_vector.h  646     0x411734: Node::~Node()
~/Dag.cpp                               138     0x409E98: Dag::~Dag()
~/main.cpp                              114     0x41062B: main
            Address 0x18 is not stack'd, malloc'd or (recently) free'd

每行调试行时,它会在以下行中断:

for (int i; i<m_dad->m_offsprings.size();++i) {
第一次迭代后

。 (在第一次调用~Dag()和第一次调用~Node()时。它从断开的for循环中的i刚刚从0变为1。 它早期打破这个事实使得它不太可能是Dag中的循环问题...... 我还有一个&#39; __ in_charg&#39;函数参数是<optimized out>(尽管-O0)。我不确定这意味着什么,但似乎Node* dummyD=m_dad;没有被阅读......

我正在寻找它不起作用的原因,逻辑中的缺陷......我知道可以使用shared_ptr为父母和weak_ptr为后代完成。

注意:术语父/后代在某种程度上是字段特定的。在这里,我在&#34; bio&#34; sens:每个人只有一个妈妈和一个爸爸,但可以有0到n个后代。

3 个答案:

答案 0 :(得分:2)

Node::~Node()函数中,似乎thism_offsprings之一。所以在

的第一次迭代之后
for (int i(0); i<m_dad->m_offsprings.size();++i) {
    if (m_dad->m_offsprings[i]) {
        m_dad->m_offsprings[i]->m_dad=nullptr;
    }
}

this->m_dad变为nullptr。之后,您尝试在m_dad->m_offsprings.size()中取消引用它。

要解决此问题,请检查当前m_dad m_offspring的地址是否不等于this。 (同样适用于m_mom。)

答案 1 :(得分:0)

不是直接的解决方案,但我想更有帮助:如果可能的话,通过使用智能指针完全摆脱所有提到的问题

Node
{
    int m_indiv;
    Node * m_dad;
    Node * m_mom;
    std::vector<std::shared_ptr<Node> > m_offsprings;
    int m_generat;
}

不,如果一个节点被破坏( - 并且它是指向后代的最后一个节点),所有后代析构函数都会自动被递归调用。因此,无需编写容易出错的代码。

答案 2 :(得分:0)

m_roots [0]和m_roots [1]共享同一个爸爸。 当你删除Node m_roots [0]时,它的&#39;爸爸和妈妈被删除,以及他们整个家庭&#34;。因此,m_roots [1]变成孤儿。