user2864293 user2864293 - 2 months ago 6
C++ Question

free works, delete segfaults on linux. Windows ok

I have some code which works ok on Windows. It segfaults on linux. When I replace the offending delete with free, it seems ok. I'm relatively new to linux, what would you recommend to debug this? I am really missing VS right now...
Here's the offending code,

#include "qtree.hh"
int main(int argc, char* argv[])
{
point a(-3, 3);
point b(3, -3);
Node* pRoot = new Node(a, b);
pRoot->addChild(se);
Node::freeTree(pRoot);

return 0;
}


freeTree() is the method that segfaults.

qtree.hh

#ifndef _QTREE_HH_
#define _QTREE_HH_

#include <cmath>
#include "Body.hh"
#include "stdio.h"
#include "stdlib.h"

enum quadrant {ne, se, sw, nw};

struct point
{
double x;
double y;

point() {}

point(double xarg, double yarg)
{
x = xarg;
y = yarg;
}
};

class Node{
public:
Node(point nw, point se);
~Node();
void addBody(const Body& body);
void addChild(quadrant q);
static void freeTree(Node* pNode);

private:
point nwPoint;
point sePoint;
point comPoint;
double mass;
double dim;
Body* pBody;

Node* nwNode;
Node* neNode;
Node* swNode;
Node* seNode;
bool bIsLeaf;
};

#endif


qtree.cc

#include "qtree.hh"

FILE* fpTree;
const bool dbg = true;

Node::Node(point nw, point se)
{
nwPoint = nw;
sePoint = se;

mass = 0;
pBody = 0;
dim = std::abs(sePoint.x - nwPoint.x);

nwNode = 0;
neNode = 0;
swNode = 0;
seNode = 0;

bIsLeaf = true;

if (dbg && !fpTree)
{
fpTree = fopen("qtree.txt", "w");
}
}

Node::~Node()
{
//close file
if (fpTree) {fclose(fpTree);}
}

void Node::addChild(quadrant q)
{
point nwP = this->nwPoint;
point seP = this->sePoint;
this->bIsLeaf = false;

switch (q)
{
case ne:
{
nwP.x = (this->sePoint.x + this->nwPoint.x)/2;
seP.y = (this->sePoint.y + this->nwPoint.y)/2;

neNode = new Node(nwP, seP);
break;
}

case se:
{
nwP.x = (this->sePoint.x + this->nwPoint.x)/2;
nwP.y = (this->nwPoint.y + this->sePoint.y)/2;

seNode = new Node(nwP, seP);
break;
}

case sw:
{
seP.x = (this->nwPoint.x + this->sePoint.x) / 2;
nwP.y = (this->nwPoint.y + this->sePoint.y)/2;

seNode = new Node(nwP, seP);
break;
}

case nw:
{
seP.x = (this->nwPoint.x + this->sePoint.x) / 2;
seP.y = (this->sePoint.y + this->nwPoint.y) / 2;

nwNode = new Node(nwP, seP);
break;
}
}

if (fpTree)
{
fprintf(fpTree, "adding child of width %f to %s corner of parent",
(this->dim)/2,
(q == nw) ? "nw" :
(q == ne) ? "ne" :
(q == se) ? "se" :
(q == sw) ? "sw" : "invalid");
}
}

void Node::addBody(const Body& body)
{

}

//will free whole tree if arg is root
//recursively free all children then free self
void Node::freeTree(Node* pNode)
{
if (pNode)
{
if (pNode->neNode)
{
if (pNode->neNode->bIsLeaf) {delete(pNode->neNode);}
else {freeTree(pNode->neNode);}
}

if (pNode->seNode)
{
if (pNode->seNode->bIsLeaf) {delete(pNode->seNode);}
else {freeTree(pNode->seNode);}
}

if (pNode->swNode)
{
if (pNode->swNode->bIsLeaf) {delete(pNode->swNode);}
else {freeTree(pNode->swNode);}
}

if (pNode->nwNode)
{
if (pNode->nwNode->bIsLeaf) {delete(pNode->nwNode);}
else {freeTree(pNode->nwNode);}
}

delete pNode;
}
}


The deletes seem to cause a problem. Free is ok. Someone is probably going to tell me not to pair free with new, but I'm out of my element and just trying different things.

Answer

The destructor of the first node closes the debug file.

The destructor of the next node closes it again. This is illegal, and will likely crash.

While we're at it, ditch the freeNode function and move the destruction to the destructor where it belongs. The destructor should look like this:

 Node::~Node()
 {
     delete nwNode;
     delete swNode;
     delete neNode;
     delete seNode;
 }

That's it. No need to check for null pointers or bIsLeaf.

Better yet, use std::unique_ptr, and ditch the destructor altogether (the rule of zero. google it).