最近使用tinyxml操作xml文件,在操作中老是看到new一个对象但是并没有delete他,作为一个C++工作者,看着很是别扭,也心存疑惑:不delete难道不会内存泄露吗?经过我上网查询,发现有很多种说法,其中一种是tinyxml将所有对象都视为doc对象的子对象(TiXmlDocument对象就是这棵树的根结点, 在一个完整的文档中, 除了它, 其余结点必须都是它的后代, 所以TinyXml用了一个很巧妙的方法来析构每一个结点所对应的对象 ---- 每个结点的析构任务都委托给了它的父亲, 这样只要保证父亲被正确析构, 或者调用了父亲的Clear函数, 它的所有后代都会被正确的析构, 所以对整个文档来说只要TiXmlDocument对象被正确析构即可。)为此我专门写了程序证实这一点,下面是我的程序
#include "E:\\vs文档\\tinyxml静态库\\tinyxml静态库\\tinyxml.h"
#include "E:\\vs文档\\tinyxml静态库\\tinyxml静态库\\tinystr.h"
#include
#include
#pragma comment(lib,"E:\\vs文档\\tinyxml静态库\\debug\\tinyxml静态库.lib")
using namespace std;
#define false 1
#define true 0
//创建xml文件
bool CreateSaveXml(string xmlfile)
{
TiXmlDocument * pDoc = new TiXmlDocument; //xml文档对象
if(NULL == pDoc)
{
return false;
}
//生成Xml声明
TiXmlDeclaration * pDeclaration = new TiXmlDeclaration("v0.0.0.1","ANSI","");//xml打头的文本申明
if(NULL == pDeclaration)
{
return false;
}
pDoc->LinkEndChild(pDeclaration);
//生成一个根节点 MyFirstXml
TiXmlElement * pRoot = new TiXmlElement("MyFirstXml");
if(NULL == pRoot)
{
return false;
}
pDoc->LinkEndChild(pRoot);
pRoot->SetAttribute("version","v0.0.0.1");
//生成第一个根节点的子节点 Message
TiXmlElement * pRFChild = new TiXmlElement("Message");
if(NULL == pRFChild)
{
return false;
}
pRoot->LinkEndChild(pRFChild);
//生成Message的第一个子节点Hello
TiXmlElement * pMFChild = new TiXmlElement("Hello");
if(NULL == pMFChild)
{
return false;
}
pRFChild->LinkEndChild(pMFChild);
//设置Hello节点的值
string HelloValue = "Welcome to my first xml";
TiXmlText * pHelloValue = new TiXmlText(HelloValue.c_str());
pMFChild->LinkEndChild(pHelloValue);
//生成Message的第二个子节点Congratulations
TiXmlElement *pMSChild = new TiXmlElement("Congratulations");
if(NULL == pMSChild)
{
return false;
}
pRFChild->LinkEndChild(pMSChild);
//设置Congratulations节点的值
string CongratulationsValue = "Congratulations on you!";
TiXmlText *pCongratulationsValue = new TiXmlText(CongratulationsValue.c_str());
pMSChild->LinkEndChild(pCongratulationsValue);
//生成第一个根节点的第二个子节点
TiXmlElement *pSRoot = new TiXmlElement("Body");
if(NULL == pSRoot)
{
return false;
}
pRoot->LinkEndChild(pSRoot);
//生成Body的第一个子节点
TiXmlElement *pBFChild = new TiXmlElement("words");
pSRoot->LinkEndChild(pBFChild);
//设置节点的值
string titlevalue = "every body woo~";
TiXmlText *ptitlevalue = new TiXmlText(titlevalue.c_str());
pBFChild->LinkEndChild(ptitlevalue);
//生成body的第二个子节点
TiXmlElement *pBSChild = new TiXmlElement("mainbody");
pSRoot->LinkEndChild(pBSChild);
pBSChild->SetAttribute("name","MainFrame");
pBSChild->SetAttribute("x","5");
/*pBSChild->SetAttribute(_T("y"),_T("15"));
pBSChild->SetAttribute(_T("w"),_T("400"));
pBSChild->SetAttribute(_T("h"),_T("250"));*/
//设置节点的值
string mainbodyvalue = "every body hands up~";
TiXmlText *pmainbodyvalue = new TiXmlText(mainbodyvalue.c_str());
pBSChild->LinkEndChild(pmainbodyvalue);
pDoc->SaveFile(xmlfile.c_str()); //保存xml文档
delete pDoc; //这里是关键
return true;
}
int main()
{
string xmlfile = "E:\\a.xml";
if(CreateSaveXml(xmlfile) == 0)
{
cout << "Xml文档创建成功" << endl;
}
else
{
cout << "Xml文档创建失败" << endl;
}
cout << endl;
解析xml文档
// TiXmlDocument *pdoc = new TiXmlDocument;
//pdoc->LoadFile("E:\\a.xml");
//TiXmlElement *pFirstRoot = pdoc->FirstChildElement();
//char * version = "v0.0.0.2";
//if(strcmp(version,pFirstRoot->Attribute("version")))
//{
// cout << "版本过旧,建议更新" << endl;
//}
cout << pFirstRoot->Value() << endl;
//cout << "当前版本: " << pFirstRoot->Attribute("version") << endl;
//cout<< "最新版本: " << version << endl;
//打印xml文档
/*pdoc->Print();*/
while (1)
{
CreateSaveXml(xmlfile);
}
return 0;
}
该程序做了一个非常简单的操作,就是创建一个简单的xml文档,为了检测内存泄露,我在主函数中写了一个死循环(一直创建xml文档,即一直new对象),下面我将进行两个测试:
①注释掉程序中的 delete pDoc; //这里是关键 ,即不释放根节点
下面用内存泄露检测工具看一下内存泄露问题
截图手法不行,将就着看吧!我的进程是716xml.exe
②看一下释放根节点的内存泄露问题
这里的两者比较可以看出,只要释放了根节点,就不会出现内存泄露问题
由此可以得出结论:
则只要删除根节点,在程序中pDoc,就相当于把删除了TiXmlNode,相当于调用了TiXmlNode的析构函数。