警惕rapidxml的陷阱:添加节点时,请保证变量的生命周期
http://www.cnblogs.com/chutianyao/p/3246592.html
项目中要使用xml打包、解析协议,HQ指定了使用rapidxml--号称是最快的xml解析器。
功能很快完成了,但发现rapidxml为了追求性能,做了一些对用户来说并不友好的设计。下面来说一说:
给xml对象在添加节点时,不可添加临时变量
按照一般用法,使用如下方式添加节点:

rapidxml::xml_document<> doc; void addNode(std::string value)
{
rapidxml::xml_node<>* root = doc.allocate_node(rapidxml::node_element, "unregister_context");
doc.append_node(root); root->append_node(doc.allocate_node(rapidxml::node_element, "who_register", value.c_str()));
}

但在rapidxml中这么写实有问题的,得这么写:

rapidxml::xml_document<> doc; void addNode(std::string value)
{
rapidxml::xml_node<>* root = doc.allocate_node(rapidxml::node_element, "unregister_context");
doc.append_node(root); root->append_node(doc.allocate_node(rapidxml::node_element, "who_register", doc.allocate_string(value.c_str())));
}

看出差别了吗?
待插入的值"变量value"是作为参数传递进来的,是临时变量。rapidxml为了追求极致性能,在append_node()函数中是直接通过指针来访问value变量的,并没有进行内存拷贝--因此rapidxml在这里提出了一个隐晦的前提条件:在xml对象doc的生命周期内,必须保证"变量value"能够被正常访问。
那么实际情况呢?
仔细检查一下,就会发现"变量value"是临时变量,在addNode()函数执行完毕后就会被销毁;此时xml对象rapidxml::xml_document<> doc内部保存的值还指向“变量value”的内存地址,而该地址已经不可用了。因此在访问xml对象时就会发生segment fault。
问题出现了,该怎么解决?我们是无法控制临时变量的生命周期的,因此只能对该变量进行拷贝。rapidxml已经提供了该功能,这就是allocate_string()函数。该函数在rapidxml对象内部的内存池中为我们的变量申请了一份内存,然后将“变量value”的值拷贝过去;由于是xml对象自己维护该内存池,因此就不存在变量地址失效的问题了。
以上情况仅针对allocate_node()待插入的值是临时变量这种情况;如果用户能保证待插入变量的生命周期、或者是常量,应该不需要使用allocate_string()函数来分配内存了。例如:
rapidxml::xml_node<>* root = doc.allocate_node(rapidxml::node_element, "data_coming", "some data");
这里第三个参数"some data"是常量,生命周期等于整个程序的生命周期,因此就不用再为它分配内存了。
(ps:此种情况仅是推测,未做测试。)
在为xml对象添加节点时,请保证变量的生命周期!
总结:
rapidxml为了追求性能,减少内存拷贝,就尽可能的通过指针(内存地址)来访问用户的变量;这就对用户提出了要求:必须保证变量的生存周期,如果变量被销毁了,rapidxml就会访问无效的内存地址,引发不可控的后果。
而对于普通用户来说,一般都比较少注意到这个细节。
为了追求性能,而牺牲了一定的可用性。这种设计是否合理?
PS:刚遇到了类似的问题,解决用了个笨办法。。。
std::vector<char*> vec;
...
...
char * name = new char[128];
vec.push_back(name);
...
最后xml的doc保存后将vec中的堆上分配内存逐个释放。。。
日~
警惕rapidxml的陷阱:添加节点时,请保证变量的生命周期的更多相关文章
- 警惕rapidxml的陷阱(二):在Android上默认内存池分配数组过大,容易导致栈溢出
上一篇随笔中提到了,rapidxml在每个xml对象中维护了一个内存池,自己管理变量的生存周期.看起来很好,但我们在实际使用中还是出现了问题. 项目中我们的模块很快写好了,在windows和linux ...
- jquery添加节点时能有点击事件
<script> var n=0; $(".dj").on('click',function(){ ...
- angularjs动态添加节点时,绑定到$scope中
<html> <head> <meta charset="utf-8"/> <script src="https://cdn.b ...
- 为11.2.0.2 Grid Infrastructure添加节点
转自:http://www.askmaclean.com/archives/add-node-to-11-2-0-2-grid-infrastructure.html 在之前的文章中我介绍了为10g ...
- react篇章-React State(状态)-将生命周期方法添加到类中
将生命周期方法添加到类中 在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要. 每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为挂载. ...
- 转://Oracle 11gR2 硬件导致重新添加节点
一.环境描述: 这是一套五年前部署的双节点单柜11g RAC,当时操作系统盘是一块164g的单盘,没有做RAID. OS: RedHat EnterPrise 5.5 x8 ...
- delphi TreeView 从数据库添加节点的四种方法
方法一:delphi中递归算法构建treeView 过程:通过读取数据库中table1的数据,来构建一颗树.table1有两个字段:ID,preID,即当前结点标志和父结点标志.所以整个树的表示为父母 ...
- 【RAC】10grac添加节点,详细步骤
RAC物理结构 现在的RAC环境是二个节点: dbp,dbs, 这个实验就是添加节点dbi. dbp,dbs和dbi节点的信息规划如下: 服务器主机名 dbp dbs dbi 公共IP地址(eth0) ...
- jquery 添加节点的几种方法介绍
<html> <head> <meta http-equiv="Content-Type" content="text/html; char ...
随机推荐
- mvc从xheditor编辑器中获取内容时存在潜在危险
xmfdsh在使用xheditor提交要发布的文章等内容的时候出现了如下的错误: 从客户端(Content="<p style="text-align...")中检 ...
- 也可以使用如下命令更改您的默认 Shell
也可以使用如下命令更改您的默认 Shell chsh -s /bin/zsh (需要输入您的密码)
- UML组件图(转载)
概述: 组件图是不同的性质和行为.组件图用于模拟物理方面的系统. 现在的问题是什么,这些物理方面?物理方面的元素,如可执行文件,库,文件,证件等它位于在一个节点. 因此,组件图用于可视化的组织和系统组 ...
- python开发中常用的框架
以下是15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python Web应用开发框架 Django 应该是最出名的 ...
- ASP.NET制作一个简单的等待窗口
前一阵做一个项目,在处理报表的时候时间偏长,客户提出要做出一个等待窗口提示用户等待(页面太久没反映,用户还以为死了呢).在分析这一需求之后,觉得如果要实现像winform应用中的processbar太 ...
- 5种你未必知道的JavaScript和CSS交互的方法
随着浏览器不断的升级改进,CSS和JavaScript之间的界限越来越模糊.本来它们是负责着完全不同的功能,但最终,它们都属于网页前端技术,它们需要相互密切的合作.我们的网页中都有.js文件和.css ...
- JavaScript中this的工作原理以及注意事项
在JavaScript中,this 的概念比较复杂.除了在面向对象编程中,this 还是随处可用的.这篇文章介绍了this 的工作原理,它会造成什么样的问题以及this 的相关例子. 要根据this ...
- C# 中的 == 和 equals()有什么区别?
如以下代码: 1 2 3 4 5 6 7 8 9 int age = 25; short newAge = 25; Console.WriteLine(age == newAge); //t ...
- mysql date数据类型异常原因0000-00
1.数据库字段: `dri_lic_first_time` date DEFAULT NULL COMMENT '驾驶证初次领证日期', 2.异常信息 org.springframework.dao. ...
- 旨在脱离后端环境的前端开发套件 - IDT Server篇
IDT,一个基于Nodejs的,旨在脱离后端环境的前端开发套件,目的就是能让前端开发完全脱离后端的环境,无论后端是什么模板引擎(主流),都能应付自如. IDT主要包括两大部分:Server + Bui ...