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的陷阱:添加节点时,请保证变量的生命周期的更多相关文章

  1. 警惕rapidxml的陷阱(二):在Android上默认内存池分配数组过大,容易导致栈溢出

    上一篇随笔中提到了,rapidxml在每个xml对象中维护了一个内存池,自己管理变量的生存周期.看起来很好,但我们在实际使用中还是出现了问题. 项目中我们的模块很快写好了,在windows和linux ...

  2. jquery添加节点时能有点击事件

    <script>            var n=0;            $(".dj").on('click',function(){              ...

  3. angularjs动态添加节点时,绑定到$scope中

    <html> <head> <meta charset="utf-8"/> <script src="https://cdn.b ...

  4. 为11.2.0.2 Grid Infrastructure添加节点

    转自:http://www.askmaclean.com/archives/add-node-to-11-2-0-2-grid-infrastructure.html 在之前的文章中我介绍了为10g ...

  5. react篇章-React State(状态)-将生命周期方法添加到类中

    将生命周期方法添加到类中 在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要. 每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为挂载. ...

  6. 转://Oracle 11gR2 硬件导致重新添加节点

    一.环境描述:        这是一套五年前部署的双节点单柜11g RAC,当时操作系统盘是一块164g的单盘,没有做RAID.        OS: RedHat EnterPrise 5.5 x8 ...

  7. delphi TreeView 从数据库添加节点的四种方法

    方法一:delphi中递归算法构建treeView 过程:通过读取数据库中table1的数据,来构建一颗树.table1有两个字段:ID,preID,即当前结点标志和父结点标志.所以整个树的表示为父母 ...

  8. 【RAC】10grac添加节点,详细步骤

    RAC物理结构 现在的RAC环境是二个节点: dbp,dbs, 这个实验就是添加节点dbi. dbp,dbs和dbi节点的信息规划如下: 服务器主机名 dbp dbs dbi 公共IP地址(eth0) ...

  9. jquery 添加节点的几种方法介绍

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

随机推荐

  1. POJ 3258 River Hopscotch (binarysearch)

    River Hopscotch Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5193 Accepted: 2260 Descr ...

  2. 浅谈MySQL索引背后的数据结构及算法【转】

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  3. 输入格式--InputFormat和InputSplit

    1)InputFormat的类图: InputFormat 直接子类有三个:DBInputFormat.DelegatingInputFormat和FileInputFormat,分别表示输入文件的来 ...

  4. HDU5052 Yaoge’s maximum profit(LCT)

    典型的LCT操作,但是维护的是一个序列最左边减最右边的最小值,所以要维护左边减右边的最小值del[0]和一个右边减左边的最小值del[1](因为rev标记swap的时候对应的值也要交换).维护的时候d ...

  5. HDU 4287 Intelligent IME(string,map,stl,make_pair)

    题目 转载来的,有些stl和string的函数蛮好的: //numx[i]=string(sx); //把char[]类型转换成string类型 // mat.insert(make_pair(num ...

  6. POJ 2549

    Sumsets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8235   Accepted: 2260 Descripti ...

  7. 关于解压覆盖IIS文件后,新的文件不具备权限导致DMS系统无法正常运行

     向DMS的服务器端站点bin目录覆盖任何补丁文件,请注意:Web站点的bin目录中的文件,IIS的服务进程(Windows2003以上,都是对应Network Services账户)必须对这些文件具 ...

  8. hdu 4061 A Card Game

    思路: 分析:假设取的牌顺序是一个序列,那么这种序列在末尾为1时是和取牌序列一一对应的,且是符合“游戏结束时牌恰好被取完”的一种情况. 简证:1.在序列中,任一数 i 的后一个数 j 是必然要放在第 ...

  9. 在Jmeter中使用自定义编写的Java测试代码

    我们在做性能测试时,有时需要自己编写测试脚本,很多测试工具都支持自定义编写测试脚本,比如LoadRunner就有很多自定义脚本的协议,比如"C Vuser","Java ...

  10. Android NDK引用预编译的动态链接库

    NDK里有个例子: android-ndk-r10/samples/module-exports/jni一看就懂了 ———————————————————————————– 从r5版本开始,就支持预编 ...