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. ActionScript基本语法讲解

    var a:int = 3;var b:int = 4; b = 9; trace ("a的值为:"+a);trace ("b的值为:"+b); var x1: ...

  2. 17+个ASP.NET MVC扩展点,含源码{转}

    1.自定义一个HttpModule,并将其中的方法添加到HttpApplication相应的事件中!即:创建一个实现了IHttpmodule接口的类,并将配置WebConfig.在自定义的HttpMo ...

  3. 比较IE6的不同之处,与IE8 IE11 比较

    文档申明为  <!DOCTYPE html> IE6或者IE特有的一些东西 1.盒子模型 IE6:(使用 !DOCTYPE 声明指定 standards-compliant 模式) mar ...

  4. ASP.NET母版页与内容页相对路径的问题

    1. 图片问题 图片显示问题:<img runat="server" src="~/images/ad468x60.gif" alt="&quo ...

  5. 报名|「OneAPM x DaoCloud」技术公开课:Docker性能监控!

    如今,越来越多的公司开始 Docker 了,「三分之二的公司在尝试了 Docker 后最终使用了它」,也就是说 Docker 的转化率达到了 67%,同时转化时长也控制在 60 天内. 既然 Dock ...

  6. CRF++中文分词使用指南

    http://blog.csdn.net/marising/article/details/5769653 前段时间写了中文分词的一些记录里面提到了CRF的分词方法,近段时间又研究了一下,特把方法写下 ...

  7. Message,MessageQueue,Looper,Handler详解

    Message,MessageQueue,Looper,Handler详解   一.几个关键概念 1.MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方.每一个线程最 ...

  8. Android的px、dip、sp的区别

    Android的px.dip.sp的区别 我们在页面布局的时候,经常会设置容器的长度,但是到底该使用哪个作为长度的单位而懊恼. 在Android中支持的描述大小区域的类型有以下几种:   px(pix ...

  9. Xamarin for Visual Studio 3.11.666 Beta版 破解补丁

    注意:本版本是 Beta 版   现已推送到稳定频道 前提概要 全新安装请参考 安装 Xamarin for Visual Studio. 最新稳定版请参考 Xamarin for Visual St ...

  10. CamShift算法

    拟采用的方法,CamShift算法,即"Continuously Apative Mean-Shift"算法,是一种运动跟踪算法.它主要通过视频图像中运动物体的颜色信息来达到跟踪的 ...