奇怪的错误 0xC0000005

skyfree 2008-06-25 05:00:16
做一个简单的xml树的解析, 出现下面的错误:
Unhandled exception at 0x734391e8 in xmlFileTree.exe: 0xC0000005: Access violation reading location 0x00000000.

代码如下所示:问题在于:在SelectSpecificFolder()内部调用GetFolderName()完全没有问题,但是通过参数将pXmlFolder传回来,再调用就会出错,本人对c++一直是一知半解,望大家指点。

int _tmain(int argc, _TCHAR* argv[])
{
CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);

XmlDocument myDoc(_T(".\\file.xml") );

XmlFolderElement *pXmlFolder =NULL;
if (S_OK != myDoc.SelectSpecificFolder(_T("\\music"), &pXmlFolder ) )
{
cout<<"selectSpecificFolder failed"<<endl;
}

LPTSTR folderName= pXmlFolder->GetFolderName(); //!!!这里出错!!!!

CoUninitialize();
return 0;


其中XmlDocument::SelectSpecificFolder()的实现如下:


HRESULT XmlDocument::SelectSpecificFolder(LPCTSTR folderPath, XmlFolderElement **resultFolder)
{

//字符串方面的处理,将folderPath转化成标准的xPath(省略这部分代码)
.................

MSXML2::IXMLDOMNodePtr pFolderNode =pXmlDoc->selectSingleNode(xPath);
//QueryInterface来进行接口转换
MSXML2::IXMLDOMElementPtr pFolderElement;
if ( S_OK != pFolderNode->QueryInterface(__uuidof(MSXML2::IXMLDOMElement), (void **)&pFolderElement))
{
// _com_issue_errorex(_hr, MSXML2::IXMLDOMElement, __uuidof(MSXML2::IXMLDOMElementPtr));
}

*resultFolder = &XmlFolderElement(pFolderElement) ;


LPTSTR aa= (*resultFolder)->GetFolderName(); //!!!!!!这里完全正确!!!
return S_OK;

}


GetFolderName()只是调用了系统的IXMLDOMElement的getAttribute, 这个方法的代码应该没有问题
LPTSTR XmlFolderElement::GetFolderName()
{
_variant_t folderNameVar = pFolderElement->getAttribute(_bstr_t(_T("name"))); //调用IXmlDomElement.getAttribute()出现上述错误提示!!!
return (LPTSTR)folderNameVar.bstrVal;
}


这个问题我研究了很长时间,指针参数的传递看起来都是没问题的,但就是出错。
...全文
555 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
skyfree 2008-06-30
  • 打赏
  • 举报
回复
采用tr1::shared_ptr了,因为要用到容器 ,试了一下,应该没问题 。结贴,谢谢大家
Walker-cheng 2008-06-26
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 ooily 的回复:]
C/C++ code *resultFolder = &XmlFolderElement(pFolderElement) ; //XmlFolderElement函数返回的是一个对象?那只是一个临时对象呀,你把这个临时对象指针返回回去肯定有问题


LPTSTR aa= (*resultFolder)->GetFolderName(); //!!!!!!这里完全正确!!!
return S_OK;
[/Quote]
night_legend 2008-06-26
  • 打赏
  • 举报
回复
弄不懂,边看边学习ING
mingguang7213 2008-06-26
  • 打赏
  • 举报
回复
*resultFolder = &XmlFolderElement(pFolderElement) ; //这应该改为
new XmlFolderElement(pFolderElement);
mingguang7213 2008-06-26
  • 打赏
  • 举报
回复
MSXML2::IXMLDOMElementPtr pFolderElement; //这句释放掉了
if ( S_OK != pFolderNode->QueryInterface(__uuidof(MSXML2::IXMLDOMElement), (void **)&pFolderElement))
{
// _com_issue_errorex(_hr, MSXML2::IXMLDOMElement, __uuidof(MSXML2::IXMLDOMElementPtr));
}

*resultFolder = &XmlFolderElement(pFolderElement) ; //这用的对象还是引用,如果是饮用肯定出错


LPTSTR aa= (*resultFolder)->GetFolderName(); //!!!!!!这里完全正确!!!
skyfree 2008-06-26
  • 打赏
  • 举报
回复
 int*  fa()
{
int * a= new int(5);
return a;
}

void fb()
{

int *b = fa();
........
delete b; //这里把释放资源的任务 交给方法的使用者,感觉设计上不合理。而且容易出现疏忽的情况
}


采用什么方法可以避免上面的问题。使得可以实现类似下面的代码?

 void fb()
{
int *b = fa();
........
}


smart pointer可以么,哪一个可以? 是不是必须要有 引用计数 功能的智能指针?我简单试了试std:auto_ptr,好像不行??!!

Maxwell 2008-06-26
  • 打赏
  • 举报
回复
那么就由调用者用指针传一个进去。
dbger 2008-06-25
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 jerrywjh 的回复:]
我觉得在一个方法中申请内存,然后在方法的调用者来释放内存,会存在很大的风险,因为:
1。调用方很可能会忘记释放
2。要求调用方知道当时内存是如何申请的,也就是知道该方法的实现细节。这违反了程序设计的原则:调用方只需要知道如何调用就行了,不必了解实现。

我以前用c#,对c++不太了解,非常想知道大家遇到这种问题都是如何解决的
[/Quote]

1.COM里面有约定,就像QueryInterface后的接口在不使用时要调用Release一样。
2.CoTaskMemAlloc和CoTaskMemFree针对COM设计,只是内存的操作,不需要知道具体细节。
s039074 2008-06-25
  • 打赏
  • 举报
回复
XmlFolderElement 类中增加一个成员变量szFolderName[MAX_LENGTH_FOLDE_RNAME]
skyfree 2008-06-25
  • 打赏
  • 举报
回复
我觉得在一个方法中申请内存,然后在方法的调用者来释放内存,会存在很大的风险,因为:
1。调用方很可能会忘记释放
2。要求调用方知道当时内存是如何申请的,也就是知道该方法的实现细节。这违反了程序设计的原则:调用方只需要知道如何调用就行了,不必了解实现。

我以前用c#,对c++不太了解,非常想知道大家遇到这种问题都是如何解决的
K行天下 2008-06-25
  • 打赏
  • 举报
回复
new分配的动态内存,编译器不会管理,
需要程序员自己去管理. 这就要清楚知道什么时候释放了, 一般对于这种情况,是确定释放之后不再使用这块内存就可以释放了
dbger 2008-06-25
  • 打赏
  • 举报
回复
COM对于传递字符串建议用BSTR*,这要组件里通过SysAllocString申请的字符串,调用者可以通过SysFreeString来释放。

对应的分配内存用CoTaskMemAlloc和CoTaskMemFree。
skyfree 2008-06-25
  • 打赏
  • 举报
回复
谢谢大家,明白了, 改成 *resultFolder = new XmlFolderElement(pFolderElement) 就没问题了,
但带来了另外一个问题:内存泄露! 这个new出来的对象在哪里delete呢? 唯一的途径就是方法的调用者来负责delete,但是这种设计缺点很明显,就是方法的使用者极有可能不知道要负责释放内存。也就是说,这种设计对使用者不透明。

这种情况,大家都怎么解决呢。类似的问题困扰了我很长时间。

在方法中不能返回临时对象(栈变量)的指针或引用,往往只能通过new把变量存在堆上,这样就能保证在方法返回时该变量不被释放。但由此带来了一个内存释放的问题:该方法的使用者要负责释放内存,这违反程序设计的原则!因为使用者往往不知道方法的实现细节,很可能不会去释放该块内存。

这种情况大家如何处理?? 分不够可以再加!
Maxwell 2008-06-25
  • 打赏
  • 举报
回复
*resultFolder = &XmlFolderElement(pFolderElement)
这个XmlFolderElement返回值估计有问题,返回一个new出来应该就不会错了。
冷月清晖 2008-06-25
  • 打赏
  • 举报
回复
你再调用的时候XmlFolderElement对象已经么得了
冷月清晖 2008-06-25
  • 打赏
  • 举报
回复
&XmlFolderElement(pFolderElement)
函数返回后 这个地址被释放了吧
king_water 2008-06-25
  • 打赏
  • 举报
回复
应该是返回时一个临时变量的指针,所以不行
sukyin 2008-06-25
  • 打赏
  • 举报
回复
*resultFolder = &XmlFolderElement(pFolderElement) ;

就是这句,你的行为是taking address of temporary。

临时对象出了函数就被释放掉了。访问0地址错误。
ouyh12345 2008-06-25
  • 打赏
  • 举报
回复
崩溃的时候,跟踪堆栈
king_water 2008-06-25
  • 打赏
  • 举报
回复
把2维指针改为一维试试
加载更多回复(3)

64,683

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧