2012-09-14 41 views
0

我想弄清楚如何在C++中創建一棵樹。我已經嘗試過幾個小時的調試,並且我認爲是時候讓我再看一眼。我的問題是如果我的treeNodeClass看起來正確。現在我正在發生堆棧爆炸,因爲我從節點中刪除了兩個項目。樹本身將解析一個簡單的xml文件。這是我的代碼。C++樹指針錯誤

#include "treeNodeClass.h"

TreeNodeClass::TreeNodeClass() 
{ 
    cout << "TREENODECLASS::TREENODECLASS()" << endl; 
    attributes.clear(); 
    children.clear(); 
    data = ""; 
    height = 0; 
    parent = NULL; 
    tag = ""; 
    cout << "EXIT TREENODECLASS::TREENODECLASS()" << endl; 
} 

TreeNodeClass::TreeNodeClass(const TreeNodeClass& other) 
{ 
    cout << "TREENODECLASS::TREENODECLASS(const other)" << endl; 
    parent = NULL; 
    CopyIntoMe(other); 
    cout << "EXIT TREENODECLASS::TREENODECLASS(const other)" << endl; 
} 

TreeNodeClass::~TreeNodeClass() 
{ 
     cout << "TREENODECLASS::~TREENODECLASS()" << endl; 
     if(parent) 
     delete parent; 
     parent = NULL; 
     children.clear(); 
     attributes.clear(); 
     cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl; 
} 

void TreeNodeClass::CreateAttrib(string root, string val) 
{ 
    string attrib = root + "=" + val; 
    attributes.push_back(attrib); 
} 

void TreeNodeClass::CreateTag(string data, string name) 
{ 
    tag = name; 
    this->data = data; 
} 

list<string> TreeNodeClass::ReturnAttrib() 
{ 
    return this->attributes; 
} 

string TreeNodeClass::ReturnTag(string tag) 
{ 
    string retTag = ""; 
    if(this->tag == tag) 
    retTag = this->tag; 
    return retTag; 
} 

void TreeNodeClass::AddChildren(TreeNodeClass* c) 
{ 
if(c != NULL) 
    children.push_back(c); 
} 

TreeNodeClass& TreeNodeClass::operator=(const TreeNodeClass& other) 
{ 
cout << "TREENODECLASS& TREENODECLASS OPERATOR = " << endl; 
if(&other != this) 
{ 
    if(parent) 
    delete parent; 

    parent = NULL; 
    attributes.clear(); 
    children.clear(); 
    CopyIntoMe(other); 
} 
return *this; 
} 

void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other) 
{ 
    cout << "Copy into me" << endl; 
    tag = other.tag; 
    data = other.data; 
    attributes = other.attributes; 
    children = other.children; 
    parent = new TreeNodeClass; 
    parent = other.parent; 
    height = other.height; 
} 


void TreeNodeClass::AddParent(TreeNodeClass* p) 
{ 
    if(p) 
    { 
    parent = new TreeNodeClass; 
    parent = p; 
    } 
} 

std::vector< TreeNodeClass* > TreeNodeClass::ReturnChildren() 
{ 
    return children; 
} 


ostream& operator<<(ostream& out, const TreeNodeClass& treeNode) 
{ 
out << "NODE: " << treeNode.tag << " " << treeNode.data << endl; 
out << "CHILDREN: " << treeNode.children.size() << endl; 
out << "HEIGHT: " << treeNode.height << endl; 
out << "Attributes: "; 
for(list<string>::const_iterator iter = treeNode.attributes.begin(); iter != treeNode.attributes.end(); iter++) 
{ 
    out << *iter << " "; 
} 
out << endl; 
} 

void TreeNodeClass::SetHeight(int h) 
{ 
    height = h; 
} 

/*void function(TreeNodeClass* node) 
{ 
    cout << node << " " << *node << endl; 

} 

TreeNodeClass* function2(TreeNodeClass* node) 
{ 

    return node; 
} 

int main() 
{ 
    cout << "STARTING PROGRAM" << endl; 
    cout << "CREATING A TREE NODE CLASS " << endl; 
    TreeNodeClass* newNode; 
    TreeNodeClass* tempNode; 

    list<string> attribs; 

    newNode = new TreeNodeClass; 
    tempNode = new TreeNodeClass; 

    newNode->SetHeight(10); 

    cout << *tempNode << " " << *newNode << endl; 
    tempNode->SetHeight(20); 

    cout << *tempNode << "\n " << *newNode << endl; 

    cout << "Setting equal " << endl; 
    *tempNode = *newNode; 
    cout << *tempNode << " " << *newNode << endl; 

    tempNode->SetHeight(40); 
    cout << *tempNode << " " << *newNode << endl; 

    tempNode->AddChildren(newNode); 
    newNode->AddParent(tempNode); 
    cout << *tempNode << "\n " << *newNode << endl; 

    return 0; 
} 
*/ 

而且我想一個簡單的狀態機上使用此代碼。我基本上建立了一個列表向量來返回狀態。這是我相信給我的大部分錯誤。我一直盯着這一段時間,但我有點失落。機器會創建樹(據說)。當狀態機結束時(狀態10),它返回並且調用函數只會對yylex()進行另一次調用。感謝你目前的幫助!

TreeNodeClass* ProcessTree(TokenT token, vector <list <stateAssoc> >& vecTree, int depth) 
    { 
int state = 1; //Assume this is a new record. 
bool noState = false; 
bool update = true; 
int dex = 0; 
string root, value, data, tag; 
TreeNodeClass* treeNode; 

treeNode = new TreeNodeClass; //Assume a new node per state machine visit. 


while(state != 10) 
{ 
    switch(state) 
    { 
case 1: dex = 1; 
    break; 

case 2: state = 3; 
    noState = true; 
    root = yylval; 
    break; 

case 3: state = 4; 
    noState = true; 
    break; 

case 4: dex = 3; 
    value = yylval; 
    //cout << value << endl; 
    treeNode->CreateAttrib(root, value); 
    break; 

case 5: dex = 2; 
    data = yylval; 
    //cout << 5 << " " << yylval << " " << token << endl; 

    //If its data store as data; if tag its a start tag. 
    break; 

case 6: dex = 4; 
    //cout << token << " " << yylval << endl; 
    break; 

case 7: state = 9; 
    noState = true; 
    tag = yylval; 
    //cout << tag << token << endl; 
    if(data != "" and data != "authors") 
     treeNode->CreateTag(data, tag); 
    break; 

case 8: { 
     TreeNodeClass* childNode = new TreeNodeClass; 
     childNode = ProcessTree(token, vecTree, depth+1); 

     cout << "BEFORE PARENT" << endl; 
     childNode->AddParent(treeNode); 
     childNode->SetHeight(depth); 
     treeNode->AddChildren(childNode); 
     delete childNode; 
     childNode = NULL; 
    } 
    token = TokenT(yylex()); //Get a new token to process. 
    dex = 5; 
    break; 

case 9: state = 10; 
    noState = true; 
    update = false; 
    break; 

case 10: noState = true; 
    update = false; 
    break; 

default: cout << "Error " << endl; 
    cout << state << endl; 
    cin.get(); 
    break; 

    } 

    if(!noState) 
state = FindMatch(vecTree[dex], token); 
    else 
noState = false; 

    if(update) 
token = TokenT(yylex()); 
    else 
update = true; 
} 
return treeNode; 

}

回答

3

1.A孩子shouldn`t刪除父:

TreeNodeClass::~TreeNodeClass() 
{ 
     cout << "TREENODECLASS::~TREENODECLASS()" << endl; 
     /* Delete next 2 lines 
     if(parent) 
     delete parent; 
     */ 
     parent = NULL; 
     children.clear(); 
     attributes.clear(); 
     cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl; 
} 

2.Containers不會刪除指針 - 你應該把它記始終。簡單的方法來刪除,例如:

for (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child) 
    delete *child; 

但最好的方法 - 不要使用本地指針,並使用一些智能指針或共享指針。

3.主要功能不會刪除指針tempNodenewNode

4.如果你將使用本機指針,你應該遞歸地創建和複製每個孩子。換句話說,你會發現內存泄漏。

方法CopyIntoMe的5.Example:

void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other) 
{ 
    cout << "Copy into me" << endl; 
    tag = other.tag; 
    data = other.data; 
    attributes = other.attributes; 

    // delete each pointer to Nodes 
    foreach (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child) 
    delete *child; 
    children.clear(); 

    // Copy recursively each child 
    foreach (vector<TreeNodeClass*>::iterator child = other.children.begin(); child != other.children.end(); ++child) { 
    TreeNodeClass* new_child = new TreeNodeClass; 
    new_child->CopyIntoMe(*child); 
    children.push_back(new_child); 
    } 

    parent = other.parent; 
    height = other.height; 
} 
+0

好點。我沒有想到這一點。我來自我的OOP培訓,我們剛剛刪除了析構函數中的所有數據。這是我第一次與樹木,因此問題。 –

+0

主要功能只是測試代碼。我只是爲了精神而離開那部分。有沒有簡單(或正確)的方法來刪除一個存儲幾個指針的容器?我假設我會使用刪除調用,然後將容器中的每個n的指針設置爲NULL。 –

+0

對每個項目清除調用析構函數的容器。在這種情況下,類型指針和指針析構函數中的項不是釋放分配的內存,也不是調用對象的析構函數。 – Lex

2

這是壞:

parent = new TreeNodeClass; 
parent = p; 

這是內存泄漏。既然你正在分配內存並指向它的父母,那麼立即指向父母的東西,你永遠不能刪除分配的內存。每次調用AddParent()時,內存都將被分配並丟失。

+1

而且''CopyIntoMe'方法。 – Lex

+0

哇,我不相信我錯過了。出於某種原因,我忘了父母在班上。如果我將父指派給p,那將只複製指針正確? (這些指針已經有一段時間了)。 –

+0

是的,它會使父項成爲在TreeNodeClass中傳遞的指針。 – ryan0