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. 项目分析 NGPcontext

    NGPcontext 之前对这个一直很疑惑,我一直认为只是在机器人方面有用处,但很有疑问,正在做这方面,我想好好看看到底是怎么运行的 bool NGP::init(NGPcontext context ...

  2. js java正则表达式替换手机号4-7位为星*号

    需求: 一个手机号13152461111,由于安全性,需要替换4-7位字符串为星号,为131****1111,那么有2中玩法,一种是前端隐藏,一种是后台隐藏. 1. 前台隐藏 <!DOCTYPE ...

  3. JAVA算法系列 冒泡排序

    java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...

  4. HDOJ 1062 Text Reverse

    Text Reverse Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  5. 通过Docker配置DNS服务器

    1. 概述 DockerHub中的 sameersbn/bind 镜像提供了搭建DNS服务器的功能,本文给出使用该镜像搭建DNS服务器的例子. 2. 环境 DNS服务器主机 IP:10.11.150. ...

  6. vi/vim使用指北 ---- Introducting the ex Editor

    本章介绍ex编辑器,为什么要介绍这样一个新的编辑器呢:其实ex编辑器不能算是一个新的编辑器,vi只是它的visual model,它已经是一个更普遍,基于行的编辑器.ex提供更大机动和范围的编辑命令. ...

  7. linux权威指南 简记

    /proc 目录,linxu系统以文件形式存放进程信息,这是一个虚拟的文件系统,不占有任何磁盘空间,当读取该文件系统时,系统内核会拦截动作,并动态产生文件与目录的内容 查看该文件夹,会发现很多已数字命 ...

  8. ZOJ 1115 Digital Roots(简单,字符串与数)

    题目 //好一道水水题,可是我居然也错了那么多次,后来百度来发现是因为数据数位可能很长很长,要用字符串数组... //简单 //有坑啊——数据可能很大很大,要用字符串表示! #include<s ...

  9. HDU 1796 How many integers can you find (状态压缩 + 容斥原理)

    题目链接 题意 : 给你N,然后再给M个数,让你找小于N的并且能够整除M里的任意一个数的数有多少,0不算. 思路 :用了容斥原理 : ans = sum{ 整除一个的数 } - sum{ 整除两个的数 ...

  10. lintcode:组成最大的数

    最大数 给出一组非负整数,重新排列他们的顺序把他们组成一个最大的整数. 注意事项 最后的结果可能很大,所以我们返回一个字符串来代替这个整数. 样例 给出 [1, 20, 23, 4, 8],返回组合最 ...