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. 关于WSDL

    Message Operation 最核心的在于Operation 只要关心Operation就可以了,Operation只有Input, Output没有其他内容,是相对固定的.只要关心一下Inpu ...

  2. Notepad++ 几款实用插件简介,让你的 Notepad++ 如虎添翼

    Notepad++ 是一款非常优秀的文本编辑器,非常适合编辑源代码.Notepad++ 安装时已经附带有 Compare 等优秀插件,通过其 Plugin Manager 可以下载更多实用插件. 一. ...

  3. 安装hbase-0.98.9-hadoop2

    1. download http://124.202.164.13/files/1244000005C563FC/www.eu.apache.org/dist/hbase/stable/hbase-0 ...

  4. unity3d 自动保存

    using UnityEngine; using UnityEditor; using System; public class AutoSave : EditorWindow { private b ...

  5. Sqli-labs less 64

    Less-64 此处的sql语句为 $sql="SELECT * FROM security.users WHERE id=(($id)) LIMIT 0,1"; 示例payloa ...

  6. [转载] Linux poll机制

    原地址:http://hongwazi.blog.163.com/blog/#m=0&t=3&c=poll poll的是一种查询的方式,英文解释 :民意调查 函数原型:int poll ...

  7. Ajax的进阶学习(一)

    在Ajax课程中,我们了解了最基本的异步处理方式.本章,我们将了解一下Ajax的一些全局请求事件.跨域处理和其他一些问题. 加载请求 在Ajax异步发送请求时,遇到网速较慢的情况,就会出现请求时间较长 ...

  8. 搭建jenkins环境(linux操作系统)

    一.虚拟机安装 1)  Virtualbox安装 2)  新建镜像(将已有镜像导入) 3)   开通本地远程访问虚拟机的权限 3.1 通过本地的mac地址设置本地连接固定的ip地址.子网掩码.默认网关 ...

  9. http://linuxme.blog.51cto.com/1850814/372960

    http://linuxme.blog.51cto.com/1850814/372960 http://os.51cto.com/art/201404/435129.htm

  10. hdu2025查找最大元素

    #include<iostream> #include<stdio.h> #include<math.h> #include<stdlib.h> #in ...