RapidXML 从文件中读取 - 这里有啥问题?

Posted

技术标签:

【中文标题】RapidXML 从文件中读取 - 这里有啥问题?【英文标题】:RapidXML reading from file - what is wrong here?RapidXML 从文件中读取 - 这里有什么问题? 【发布时间】:2011-09-15 20:42:55 【问题描述】:

这两种读取输入文件的方法有什么区别?

1) 使用'ifstream.get()'

2) 将vector<char>ifstreambuf_iterator<char> 一起使用(我不太了解!)

(除了可以使用漂亮的向量方法的明显答案)

输入文件是 XML,如下所示,立即解析为 rapidxml 文档。 (在别处初始化,参见示例 main 函数。)

首先,让我向您展示两种编写“load_config”函数的方法,一种使用ifstream.get(),一种使用vector<char>

方法 1ifstream.get() 提供了工作代码和一个安全的 rapidXML 文档对象:

rapidxml::xml_document<> *load_config(rapidxml::xml_document<> *doc)
   ifstream myfile("inputfile");

   //read in config file
   char ch;
   char buffer[65536];
   size_t chars_read = 0;

   while(myfile.get(ch) && (chars_read < 65535))
      buffer[chars_read++] = ch;
   
   buffer[chars_read++] = '\0';

   cout<<"clearing old doc"<<endl;
   doc->clear();

   doc->parse<0>(buffer);

   //debug returns as expected here
   cout << "load_config: Name of my first node is: " << doc->first_node()->name() << "\n";

   return doc;

方法 2 导致另一个库破坏了 rapidXML 文档 - 具体来说,调用 curl_global_init(CURL_GLOBAL_SSL) [见下面的主要代码] - 但我还没有将其归咎于 curl_global_init。

rapidxml::xml_document<> *load_config(rapidxml::xml_document<> *doc)
   ifstream myfile("inputfile");

   vector<char> buffer((istreambuf_iterator<char>(inputfile)), 
                istreambuf_iterator<char>( ));
   buffer.push_back('\0');

   cout<<"file looks like:"<<endl;  //looks fine
   cout<<&buffer[0]<<endl;

   cout<<"clearing old doc"<<endl;
   doc->clear();

   doc->parse<0>(&buffer[0]);

   //debug prints as expected
   cout << "load_config: Name of my first node is: " << doc->first_node()->name() << "\n";

   return doc;

主要代码:

int main(void)
   rapidxml::xml_document *doc;
   doc = new rapidxml::xml_document;

   load_config(doc);

   // this works fine:
   cout << "Name of my first node is: " << doc->first_node()->name() << "\n"; 

   curl_global_init(CURL_GLOBAL_SSL);  //Docs say do this first.

   // debug broken object instance:
   // note a trashed 'doc' here if using vector<char> method 
   //  - seems to be because of above line... name is NULL 
   //    and other nodes are now NULL
   //    causing segfaults down stream.
   cout << "Name of my first node is: " << doc->first_node()->name() << "\n"; 

我非常确定这一切都是在一个线程中执行的,但也许有一些超出我理解范围的事情发生。

我还担心我只是解决了一个症状,而不是一个原因......通过简单地更改我的文件加载功能。在这里向社区寻求帮助!

问题:为什么从向量转移到字符数组可以解决这个问题?

提示:我知道 rapidXML 使用了一些巧妙的内存管理,实际上直接访问输入字符串。

提示:上面的 main 函数创建了一个动态的(新的)xml_document。这不在原始代码中,而是调试更改的工件。原来的(失败的)代码声明了它并且没有动态分配它,但是出现了同样的问题。

另一个全面披露的提示(尽管我不明白它为什么重要) - 在这个由 rapidxml::xml_document 对象中的数据填充的混乱代码中还有另一个向量实例。

【问题讨论】:

其中的sexy 是什么?这是时装秀吗? 由于唯一的区别是如何从文件中读取数据,这些问题似乎相关:***.com/questions/116038/…***.com/questions/195323/… 作为健全性检查,您能否将调试器设置为检查从 &buffer[0] 开始的内存,以便在 parse() 之前和之后的调用中查看它们是否在所有情况下都相同? 你仍然有这个错误。当你因为chars_read &lt; 65535 为假而退出循环时,这意味着chars_read == 65535 然后你访问了第65535 个位置,这是数组末尾的一个位置。 感谢 ybungalobill。根本不应该打折。注意到、赞赏和修复。 【参考方案1】:

两者之间的唯一区别是vector 版本可以正常工作,而char 数组版本在文件长度超过65535 个字符时会导致未定义的行为(它将\0 写入第65535 或第65536 位置,超出范围)。

另一个两个 版本共有的问题是,您将文件读入一个比xml_document 寿命更短的内存。 阅读文档:

字符串必须在文档的整个生命周期内持续存在。

load_config 退出时,vector 被销毁并释放内存。尝试访问文档会导致读取无效内存(未定义行为)。

char 数组版本中,内存分配在堆栈上。当load_config 存在时,它仍然被“释放”(访问它会导致未定义的行为)。但是您看不到崩溃,因为它尚未被覆盖。

【讨论】:

这当然是答案。最终也看到了 char 数组版本的问题。函数中的“静态”关键字和最终将缓冲区范围移动到主要解决的问题。谢谢!

以上是关于RapidXML 从文件中读取 - 这里有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

RapidXml用法

一次从文件中读取 512 个字节并检查里面有啥?

从其他类调用此方法会创建违规读取

RapidXML 编译错误解析字符串

TinyXml 与 Rapidxml效率对照

从 stringstream 到 string 的转换会删除 '=' 字符