程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++中遍地New卻不見delete疑問重重

C++中遍地New卻不見delete疑問重重

編輯:C++入門知識

在上篇博客中,大概了解了tinyxml工具的架構,那這篇博客,我們詳細講述如何利用tinyxml操縱xml。以及在操作的過程中,我們應該注意的問題。
    
     首先把tinyxml源文件導入自己的工程中,效果如下:
    \

    實際上,直接添加文件到工程中:如下:\
 
    若您的系統是win7或office是2007以上的,添加文件這個功能是不能用的,結果是:或直接崩潰。或沒反應。     
     環境准備好了,那麼我們開始動手操作吧。正如對數據庫表操作一樣---增刪改查。根據此邏輯,那就從增(創建)開始。
     創建的格式如下:
     <Persons>
    <Person>
        <name>lhy</name>
        <age>22</age>
    </Person>
     </Persons>
    

      上篇博客中,我們也介紹了tinyxml解析器中的所有的類以及類之間的關系。
      創建上述格式的xml,代碼如下:
[html] view plaincopyprint?
    //創建一個XML的文檔對象。 
 TiXmlDocument *myDocument = new TiXmlDocument(); 
 //創建一個根元素並連接。 
 TiXmlElement *RootElement = new TiXmlElement("Persons"); 
 myDocument->LinkEndChild(RootElement); 
 
 //創建一個Person元素並連接。 
 TiXmlElement *PersonElement = new TiXmlElement("Person"); 
 RootElement->LinkEndChild(PersonElement); 
 
 //創建name元素、age元素並連接。 
 TiXmlElement *NameElement = new TiXmlElement("name"); 
 TiXmlElement *AgeElement = new TiXmlElement("age"); 
 
 PersonElement->LinkEndChild(NameElement); 
 PersonElement->LinkEndChild(AgeElement); 
 
 //設置name元素和age元素的內容並連接。 
 TiXmlText *NameContent = new TiXmlText("lhy"); 
 TiXmlText *AgeContent = new TiXmlText("22"); 
 
 NameElement->LinkEndChild(NameContent); 
 AgeElement->LinkEndChild(AgeContent); 
 
myDocument->SaveFile("d:\\lhy\\xml.txt");//保存到文件 

        //創建一個XML的文檔對象。
     TiXmlDocument *myDocument = new TiXmlDocument();
     //創建一個根元素並連接。
     TiXmlElement *RootElement = new TiXmlElement("Persons");
     myDocument->LinkEndChild(RootElement);
   
     //創建一個Person元素並連接。
     TiXmlElement *PersonElement = new TiXmlElement("Person");
     RootElement->LinkEndChild(PersonElement);
   
     //創建name元素、age元素並連接。
     TiXmlElement *NameElement = new TiXmlElement("name");
     TiXmlElement *AgeElement = new TiXmlElement("age");
   
     PersonElement->LinkEndChild(NameElement);
     PersonElement->LinkEndChild(AgeElement);
   
     //設置name元素和age元素的內容並連接。
     TiXmlText *NameContent = new TiXmlText("lhy");
     TiXmlText *AgeContent = new TiXmlText("22");
   
     NameElement->LinkEndChild(NameContent);
     AgeElement->LinkEndChild(AgeContent);
  
    myDocument->SaveFile("d:\\lhy\\xml.txt");//保存到文件
   
     只要搞清xml中節點之間的關系,創建不是問題。說白了就是一種輩分關系。
    創建搞定了,但是作為C++程序猿,寫完之後,總感覺有點別扭,總感覺哪不對勁。你是否也看出其中存在的貓膩?
    對了,些許的代碼中有大量的New指針。在C++中可沒有java中的垃圾回收機制,必須自己來處理這些廢棄的垃圾。但是代碼中卻沒有Delete語句?
 
   上網查了資料,發現很多創建代碼中,都沒有Delete語句?難道是大家都是復制粘貼?還是tinyxml在搞怪?
    我總結了以下幾點,但是最後在開發的過程中仍是疑問,但是開發的過程中,沒有出現問題,所以我的程序就暫時如此了。
    說法一:很多文章中,都是new沒有delete,是因為tinyxml可以自動釋放,自動銷毀指針,無需開發者手動釋放。
    質疑:new出來的可以自動釋放?new出來說明是在堆上創建的,什麼時候會自動釋放?程序結束時,自動釋放?那怎麼判斷程序結束呢?(在一個模塊中如何析構另一個模塊中的內存區域,我們後面會詳談),所以這種說法不攻自破。
    既然tinyxml中有自毀功能,那我們查詢其源代碼,發現果真如此,tinyxml中在析構函數中,有相應的指針釋放。但是並不是每個節點如此的。
     源碼中的詳情:
[html] view plaincopyprint?
TiXmlNode::~TiXmlNode() 

     TiXmlNode* node = firstChild; 
     TiXmlNode* temp = 0; 
 
     while ( node ) 
     { 
          temp = node; 
          node = node->next; 
          delete temp; 
     }     

void TiXmlNode::Clear() 

     TiXmlNode* node = firstChild; 
     TiXmlNode* temp = 0; 
 
     while ( node ) 
     { 
          temp = node; 
          node = node->next; 
          delete temp; 
     }     
 
     firstChild = 0; 
     lastChild = 0; 

TiXmlNode::~TiXmlNode()
{
     TiXmlNode* node = firstChild;
     TiXmlNode* temp = 0;

     while ( node )
     {
          temp = node;
          node = node->next;
          delete temp;
     }   
}
void TiXmlNode::Clear()
{
     TiXmlNode* node = firstChild;
     TiXmlNode* temp = 0;

     while ( node )
     {
          temp = node;
          node = node->next;
          delete temp;
     }   

     firstChild = 0;
     lastChild = 0;
}
  我們也知道tinyxml中的類之間存在繼承關系。
  那我們看tinyxml中的TixmlElement類:
[html] view plaincopyprint?
TiXmlElement::~TiXmlElement() 

     ClearThis(); 

void TiXmlElement::ClearThis() 

     Clear(); 
     while( attributeSet.First() ) 
     { 
          TiXmlAttribute* node = attributeSet.First(); 
          attributeSet.Remove( node ); 
          delete node; 
     } 

TiXmlElement::~TiXmlElement()
{
     ClearThis();
}
void TiXmlElement::ClearThis()
{
     Clear();
     while( attributeSet.First() )
     {
          TiXmlAttribute* node = attributeSet.First();
          attributeSet.Remove( node );
          delete node;
     }
}
    因為TixmlElement是繼承TiXmlNode.但是在TiXmlDocument中並沒有發現TiXmlDocument類的析構函數。
   第二種說法:TiXmlDocument對象就是這棵樹的根結點, 在一個完整的文檔中, 除了它, 其余結點必須都是它的後代, 所以TinyXml用了一個很巧妙的方法來析構每一個結點所對應的對象 ---- 每個結點的析構任務都委托給了它的父親, 這樣只要保證父親被正確析構, 或者調用了父親的Clear函數, 它的所有後代都會被正確的析構, 所以對整個文檔來說只要TiXmlDocument對象被正確析構即可。
在創建的上述代碼中,我們發現,所有的節點都是掛在根節點之下的。
   其實這句代碼: myDocument->LinkEndChild(RootElement);使用了多態方式。類之間的關系如下:
\ 
   
   並且LinkEndChild源代碼如下:它是父類TiXmlNode中的方法
[html] view plaincopyprint?
TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) 

     assert( node->parent == 0 || node->parent == this ); 
     assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); 
 
     if ( node->Type() == TiXmlNode::DOCUMENT ) 
     { 
          delete node; 
          if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); 
          return 0; 
     } 
     node->parent = this; 
     node->prev = lastChild; 
     node->next = 0; 
     if ( lastChild ) 
          lastChild->next = node; 
     else 
          firstChild = node;               // it was an empty list. 
 
     lastChild = node; 
     return node; 

TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
{
     assert( node->parent == 0 || node->parent == this );
     assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );

     if ( node->Type() == TiXmlNode::DOCUMENT )
     {
          delete node;
          if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
          return 0;
     }
     node->parent = this;
     node->prev = lastChild;
     node->next = 0;
     if ( lastChild )
          lastChild->next = node;
     else
          firstChild = node;               // it was an empty list.

     lastChild = node;
     return node;
}
    這樣的話:則只要刪除根節點,在程序中myDocument,就相當於把刪除了TiXmlNode,相當於調用了TiXmlNode的析構函數。
    質疑:網上說這種方式,析構是從葉子到樹根。根據TiXmlNode中的析構函數,我們可以得出,是從樹根到葉子。
  
   但是我們在Delete myDocument時,應該注意一點:
   創建文檔時,也就是程序段中的myDocument。若是從堆上創建,則需需要手動釋放。如我們上述的片段中,就是在堆上創建的。
   TiXmlDocument *myDocument=new TiXmlDocument ();
   若是從棧上創建,則不須我們手動釋放,而是程序自動調用析構函數。同時我們應該注意,其他的元素必須在堆上創建。因為在TiXmlNode析構函數中,是delete的,但是棧上的東東是不須delete,所以除了根節點之外連接的後代節點是必須從堆上創建。


   經過我們解釋,明白tinyxml中的原理了嗎?只要理解了tinyxml中的類的作用以及類之間的關系,看源碼是沒問題滴哦。

   這篇博客根據創建xml小demo解釋了其中存在的疑問。那下篇博客中我們會根據解析xml來答疑解析中存在的問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved