0

C++ でツリーを作成する方法を理解しようとしています。私はこれを何時間もデバッグしようとしましたが、別の目を向ける時が来たと思いました。私の質問は、私の treeNodeClass が正しいかどうかです。現在、ノードからアイテムを二重に削除しているため、スタック爆発が発生しています。ツリー自体は単純な xml ファイルを解析します。これが私のコードです。

#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;

}

4

2 に答える 2

3

1.子供は親を削除すべきではありません:

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.コンテナーはポインターを削除しません。常に念頭に置いておく必要があります。たとえば、次のように簡単に削除できます。

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

ただし、最善の方法は、ネイティブ ポインターを使用せず、スマート ポインターまたは共有ポインターを使用することです。

tempNode3.Main 関数はポインタと を削除しませんnewNode

4.ネイティブ ポインターを使用する場合は、各子を再帰的に作成してコピーする必要があります。他の方法では、メモリリークをキャッチします。

5.方法例CopyIntoMe

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; 
}
于 2012-09-14T04:08:57.333 に答える
2

これは悪いです:

parent = new TreeNodeClass;
parent = p; 

これはメモリリークです。メモリを割り当てて親をそのメモリにポイントし、すぐに親を別のメモリにポイントするため、割り当てられたメモリを削除することはできません。AddParent()が呼び出されるたびに、メモリが割り当てられ、失われます。

于 2012-09-14T04:23:52.943 に答える