警惕rapidxml的陷阱:添加节点时,请保证变量的生命周期
2013-08-09 14:21
253 查看
项目中要使用xml打包、解析协议,HQ指定了使用rapidxml--号称是最快的xml解析器。
功能很快完成了,但发现rapidxml为了追求性能,做了一些对用户来说并不友好的设计。下面来说一说:
[b]给xml对象在添加节点时,不可添加临时变量[/b]
按照一般用法,使用如下方式添加节点:
但在rapidxml中这么写实有问题的,得这么写:
看出差别了吗?
待插入的值"变量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()函数来分配内存了。例如:
这里第三个参数"some data"是常量,生命周期等于整个程序的生命周期,因此就不用再为它分配内存了。
(ps:此种情况仅是推测,未做测试。)
在为xml对象添加节点时,请保证变量的生命周期!
总结:
rapidxml为了追求性能,减少内存拷贝,就尽可能的通过指针(内存地址)来访问用户的变量;这就对用户提出了要求:必须保证变量的生存周期,如果变量被销毁了,rapidxml就会访问无效的内存地址,引发不可控的后果。
而对于普通用户来说,一般都比较少注意到这个细节。
为了追求性能,而牺牲了一定的可用性。这种设计是否合理?
功能很快完成了,但发现rapidxml为了追求性能,做了一些对用户来说并不友好的设计。下面来说一说:
[b]给xml对象在添加节点时,不可添加临时变量[/b]
按照一般用法,使用如下方式添加节点:
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就会访问无效的内存地址,引发不可控的后果。
而对于普通用户来说,一般都比较少注意到这个细节。
为了追求性能,而牺牲了一定的可用性。这种设计是否合理?
相关文章推荐
- 警惕rapidxml的陷阱:添加节点时,请保证变量的生命周期
- 警惕rapidxml的陷阱(二):在Android上默认内存池分配数组过大,容易导致栈溢出
- 警惕rapidxml的陷阱(二):在Android上默认内存池分配数组过大,容易导致栈溢出
- 如何在node节点的评论下面添加想要…
- CDH5 添加数据节点
- C# XML 添加,修改,删除Xml节点
- hudson内置环境变量添加
- Mac 可设置环境变量的位置、查看和添加PATH环境变量
- Windows 如何在cmd命令行中查看、修改、删除与添加环境变量
- ubuntu环境变量的添加与删除
- Raphaël的动态线条添加,节点拖拽
- C++旧源码向新标准移植陷井(一)_局部栈变量的生命周期
- table中动态添加图片节点
- windows创建添加系统变量
- C/C++中的变量作用域,生命周期,初始值
- QT使用rapidxml解析XML之删除固定节点
- Js(DOM)动态添加节点和事件
- 在mac下添加环境变量
- liunx centos 添加环境变量
- VS2012,MFC中编辑框右击属性添加变量,未弹出对话框--已解决