DAG 析构函数出错
Error in DAG destructor
我有一个 Dag class(有向无环图),其中包含指向 class 节点对象的原始指针向量。该向量称为 m_roots
,由所有没有后代的节点组成。 (但它们最多可以有两个父节点)Node 对象形成了某种二叉树。
Nodes的成员属性为:
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()
{
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;
}
}
出于某种原因,这不起作用:我遇到段错误。
对应的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 中的循环问题......
我还有一个“__in_charg”函数参数,它是 <optimized out>
(尽管 -O0)。我不确定这是什么意思,但似乎 Node* dummyD=m_dad;
没有被读取...
我正在寻找它不起作用的原因,逻辑中的缺陷...我知道可以使用 shared_ptr
来完成妈妈和爸爸,使用 weak_ptr
来完成后代。
注意: 术语 parent/offspring 在某种程度上是特定领域的。这里我在"biological"意义上使用它:每个人只有一个妈妈和一个爸爸,但可以有 0 到 n 个后代。
不是直接的解决方案,但我想更有帮助:如果可能的话,通过使用智能指针完全摆脱所有提到的问题
Node
{
int m_indiv;
Node * m_dad;
Node * m_mom;
std::vector<std::shared_ptr<Node> > m_offsprings;
int m_generat;
}
不,如果一个节点被析构(——它是最后一个指向后代的节点),所有后代析构函数都会自动递归调用。因此,无需再编写容易出错的代码。
m_roots[0] 和 m_roots[1] 同父异母。
当您删除节点 m_roots[0] 时,它的父亲和母亲以及它们的整个 "family" 都会被删除。因此,m_roots[1]成为孤儿。
在Node::~Node()
函数中,好像this
是m_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
也一样。)
我有一个 Dag class(有向无环图),其中包含指向 class 节点对象的原始指针向量。该向量称为 m_roots
,由所有没有后代的节点组成。 (但它们最多可以有两个父节点)Node 对象形成了某种二叉树。
Nodes的成员属性为:
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()
{
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;
}
}
出于某种原因,这不起作用:我遇到段错误。 对应的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 中的循环问题......
我还有一个“__in_charg”函数参数,它是 <optimized out>
(尽管 -O0)。我不确定这是什么意思,但似乎 Node* dummyD=m_dad;
没有被读取...
我正在寻找它不起作用的原因,逻辑中的缺陷...我知道可以使用 shared_ptr
来完成妈妈和爸爸,使用 weak_ptr
来完成后代。
注意: 术语 parent/offspring 在某种程度上是特定领域的。这里我在"biological"意义上使用它:每个人只有一个妈妈和一个爸爸,但可以有 0 到 n 个后代。
不是直接的解决方案,但我想更有帮助:如果可能的话,通过使用智能指针完全摆脱所有提到的问题
Node
{
int m_indiv;
Node * m_dad;
Node * m_mom;
std::vector<std::shared_ptr<Node> > m_offsprings;
int m_generat;
}
不,如果一个节点被析构(——它是最后一个指向后代的节点),所有后代析构函数都会自动递归调用。因此,无需再编写容易出错的代码。
m_roots[0] 和 m_roots[1] 同父异母。 当您删除节点 m_roots[0] 时,它的父亲和母亲以及它们的整个 "family" 都会被删除。因此,m_roots[1]成为孤儿。
在Node::~Node()
函数中,好像this
是m_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
也一样。)