Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)

所需积分/C币:9 2015-06-23 13:02:54 8.53MB PDF

Boost程序库探秘 深度解析C++准标准库(251-300) (第二版),只有我这里有全套的,赶紧来下载吧! (251-300)是指页数
520总结 253 typedef ptr vector<item> ptr vec; //使用之前的item类定义 ptr vec veci using namespace boost: assign: ptr push back<television>(vec)()i ptr push back< computer>(vec)()i ptr vec v2: v2. transfer(v2. begin(),vec, begin(),vec);//可以使用转移所有权操作 但下面的代码由于使用了克隆操作所以无法通过编译: ptr vec v2(vec): //克隆构造 v2= vec clone(); //调用克隆方法 另外有些情况下代码里虽然没有明显的容器克隆,但却存在隐含的克隆操作,这时也会 导致编译失败: typedef std: mapsintr ptr vec> wrong map; //标准容器要求拷贝语义 wrong map iti m[1] / operator[]发生克隆,编译错误 总的来说,由于指针容器仅存储指针,所以大大降低了对元素的要求,虽然有的操作需 要使用克隆,但因为存在 new clone()和 delete c1one()函数的缺省实现,几乎无须任 何多余的工作就可以使用 ptr container库的全部能力。不过对于不可拷贝的类型来说, 必须像在标准容器里使用它们时一样谨慎,必要 5.196序列化 2 tr container库的所有指针容器都支持序列化,容器的序列化头文件位于目录 st/ ptr container/>下,详细的讨论见第9章9.8,5小节。 520总结 本章讨论了 Boost库中的指针容器,它专门用于容纳指针元素,提供了与标准容器等 价的 ptr vector、ptr1ist等各种容器,而且是异常安全的,保证没有内存泄漏。 ptr container库里的指针容器基本与标准容器对应,接口和用法也非常相近,但它 的根本特点是容器里容纳的是指针而不是元素的拷贝,因此存在许多与标准容器不同的地方。 Boost程序库探秘——深度解析C艹+准标准库(第2版) 254 第5章指针容器 指针容器对元素的要求非常低,不需要元素是可拷贝或可赋值的,因此几乎可以容纳任 意类型的元素—包括 auto ptr。指针容器也可以存储多态对象的指针,成为一个多态容 器,这在很多时候都是非常有用的。 谈到指针就离不开空指针,虽然指针容器允许使用包装类nu11ab1e<T>来容纳空指针, 但这种做法很不安全,也很容易出错,应该尽量使用空对象模式来代替空指针的使用。 克隆是指针容器的一个特有概念,它类似标准容器中的内存分配器概念(a1 orator), 可以在需要的时候创建指针所指对象的拷贝。 ptr container库提供缺省的克隆分配器实 现,但这不是必须的,很多指针容器的操作无须克隆概念也可以工作。 ptr container库提供了数量众多的指针容器,因此必须对指针容器的优缺点做到心 中有数,充分发挥它们的优点同时避免它们的缺点。在使用时首先要决策是使用标准容器还 是指针容器,标准容器容纳智能指针用法通用灵活,而指针容器有指针不可共享的限制,但 用起来更方便。第二个决策是使用何种指针容器,由于指针容器与标准容器基本等价,因此 可以参照标准容器的使用策略,最常用的是向量指针容器 ptr vector。 ptr container库内容十分丰富,可以说与标准库不相上下,读者可在阅读完本章后 进一步参考Bo¤st文档和源码深入研究。 Boost程序库探秘——深度解析C艹-准标准库(第2版) 第b章 侵入式容器 本章我们将看到另外一类新式容器:侵入式容器。 侵入式容器名字中的“侵入”一词容易令人产生不愉快的联想,但它并没有任何恶意。 侵入式容器也是一类用于容纳元素的容器,但元素必须做出一些代码上的适度修改才能被容 纳,因此,侵入式容器看起来像是“侵犯/闯入”了元素的内部实现,而实际上,我们对侵 入式容器并不陌生,最早在数据结构课程中实现的链表、二叉树等数据结构都属于侵入式容 器的范畴。 与侵入式容器相对应的是非侵入式容器。标准容器和第5章介绍的指针容器都属于非侵 入式容器,这类容器不要求对容纳的元素做任何修改即可容纳,较侵入式容器实现手法要温 和很多。因为非侵入式容器用起来简单方便,自C++标准库出现后非侵入式容器逐渐大行其 道,侵入式容器却日薄西山。 但侵入式容器也有自己的优点,它没有非侵入式容器的拷贝、克隆等要求,也可以保存 抽象类,对内存管理的要求很低,而且允许定制数据结构,所以通常可以提供更好的性能。 Boost使用库 intrusive重新引入了侵入式容器,而且具有近似标准容器的接口,大大降 低了应用的难度,值得我们去学习使用。 6.1概述 在这一节中我们将展示 intrusive库的大致轮廓,了解它的一些基本概念。为了让读 者对侵入式容器有一个比较明晰的印象,我们先来回顾一下数据结构的知识 Boost程序库探秘——深度解析C艹+准标准库(第2版) 256 第6章侵入式容器 6.1.1手工实现链表 读者应该对数据结构不会陌生,许多学校都会教授这个课程,线性表、链表、二叉树、 堆等数据结构是计算机科学的基础,构建这些数据结构是一个程序员应该具备的基本素质。 遗憾的是自从完整精致的sTL横空出世,这一基本功就渐渐被大多数人荒废了(笔者也是其 中之一,惭愧)。下面我们来实现一个最简单的单向链表结构,它是一个最简单的侵入式容器。 首先定义一个简单的节点类 point: class point: boost: noncopyable /简单的节点类,不可拷贝和赋值 public: int xyi //节点的“有效载荷” //下面的代码是构造链表所需的“附件” typedef point* node ptr; //指针类型定义 node ptr nex七 //后继指针 point(int a=0, int b=0) //构造函数 x(a), y(b), next(NULL)I H /后继初始化为空指针,即无后继 node ptr get next () /获得后继节点 1 return nextiI void set next (node ptr p) //设置后继节点 next p }; point类的真正作用是保存坐标值,但为了实现链表必须增加一个额外的存储空间:后 继指针变量neκt。为了规范指针的使用,我们定义了两个get/set成员函数,这种间接层 比直接操作指针要好的多。 下面的代码示范了节点类是如何连接成链表并使用的: int main () point p1,p2(2,2),p3(3,3); //三个节点对象,未连接 p1, set next(sp2)氵 //p1连接p2,链表形如p1->p2 p2. set next(&p3)i //p2连接p3,链表形如p1->p2->p3 ①后面我们会看到 intrusive库同样使用了这样的实现手法 Boost程序库探秘——深度解析C艹+准标准库(第2版) 6.1概述 257 for (point:: node ptr p &pli //指向头节点 p ! nullptr //循环终止条件 p= p->get next()) //指针前进到下一个节点 cout<p→>x<<"-"<<P->y<<"" pl, set next(&p3)i //从链表中移除p2,链表形如p1->p3 这个简单的例子展示了侵入式容器的一些重要特性: 首先,元素除了它自身的必备功能外还必须要增加一些额外的能力(这里是指向后继节 点的指针)才能被纳入侵入式容器(链表)。其次,侵入式容器不负责内存分配,元素的创建 是容器之外的事情,与它无关。第三,侵入式容器并不真正的“容纳”对象,元素仍然散落 在内存中的各个位置,仅仅是使用指针以某种算法(这里是单向顺序算法)把它们连接起来 便于访问而已,某种程度上把它称为“链接视图”或许会更恰当。最后,侵入式容器的插入 删除等操作也只是操纵链接的指针,调整元素的链接顺序,不涉及内存的分配管理 6.1.2 intrusive库介绍 intrusive库位于名字空间 boost:: intrusive,由数个不同的头文件组成,实现 了许多非常有用的侵入式容器,它们都位于目录< boost/ intrusive/>下,使用具体的容 器时包含所需头文件即可。 因为侵入式容器都是使用指针链接实现的,所以也可以称为“链式容器”——不存在与 std: vector、std:: deque等价的基于数组实现的容器 intrusive库提供的侵入式容器都具有与标准容器类似的接口,包括: slist :单向链表; list :类似std::list的双向链表,是 最常用的侵入式容器; set/multiset/rbtree 基于红黑树的类似std::set的关 联容器; avl set/avl multiset/avltree :基于AVL树的类似std::set的关 联容器 ■ splay set/ splay multiset/ splaytree:基于 splay树的类似std::set 的关联容器; Boost程序库探秘——深度解析C++准标准库(第2版) 258 第6章侵入式容器 a sg set/sg multiset/stree 基于 scapegoat树的类似 std::set的关联容器; a treap set/treap multiset/treap :基于堆二叉树的类似std::set的 关联容器; ■ unordered set/ unordered multiset:无序关联容器。 根据侵入的程度这些容器又可分为纯侵入式容器( intrusive container)和半侵入 式容器(semi- intrusive container)。 intrusive库提供的大多数容器都属于纯侵入式容器( intrusive container), 仅仅调整节点中的链接指针,并没有“容纳”任何东西。 unordered set和 unordered multiset这两个无序关联容器属于半侵入式容器,这是因为它们需要一个额 外的内存空间来维护散列容器所需的负载因子(1 bad factor),不是完全的侵入 侵入式容器的一个重要特点是它不负责管理元素的生命周期,仅仅是调整指针的链接, 因此没有对象拷贝的运行开销,元素的创建工作被外部化,这与标准容器(使用内存分配器) 和指针容器(使用克隆分配器)是明显不同的。带来的好处是最小化了内存使用,提高了运 行效率。但这也同时是侵入式容器的缺点,因为内存管理的工作终归是有人要做,那么现在 就交给了用户—元素的创建与删除对于侵入式容器来说是一个重要的工作,有些时候我们 可以使用第5章的指针容器来简化。更进一步的推论是,侵入式容器与容纳的元素两者的生 存期是不一致的,有可能因为元素被销毁而导致访问失败,所以元素的生命周期应该比侵入 式容器要长。 62入门示例 使用侵入式容器必须要修改自有类的定义,为此 Intrusive库提供了挂钩(hook)这 方便的工具类,它包含了一些必要的数据,可以把它近似地理解为链接指针的聚合。挂钩 可以分为基类挂钩( base hook)和成员挂钩( member hook)两类,可以以基类或者成 员的方式嵌入到自有类中使用 下面我们使用单链表来示范侵入式容器的基本用法,其中涉及的概念参见6.3小节。 62.1使用基类挂钩 单链表侵入式容器使用的基类挂钩是s1 ist base hook,并不需要我们做太多的工 作,只要从它继承就可以了。 point类可以改写成如下的形式: Boost程序库探秘——深度解析C++准标准库(第2版) 6,2入门示例 259 include <boost/intrusive/slist hpp> //单链表侵入式容器 using namespace boost: :intrusive //侵入式容器的名字空间 class point: public slist base hook<> //使用基类挂钩,缺省配置 public: nt x, yi //无须自定义链接指针,已由挂钩实现 point(int a =0, int b=0): x(a);y(b)( 单链表侵入式容器s1ist具有类似标准容器的接口,可以这样使用: int main() point p1,p2(2,2),p3(3,3);//3个节点对象,未连接 slist<point> sli //声明一个单链表侵入式容器,缺省配置,可容纳 point sl push front(pl) //缺省情况下不能使用 push back() sl push front(p2)i sl push front(p3)i //链表形如p3->p2->p1 assert (sl size()==3)i l reverse /提供内置的逆序算法,链表形如p1->p2->p3 for(point& p: sl) //可以使用新式for循环 cout <s pX <<-<<py s1. erase( boost::next(s1, begin()));//删除链表中的第二个节点 s1is是 intrusive库提供的一个单链表容器,缺省情况下只能使用 push front() 添加元素,如果在sist的模板参数中增加一个配置选项 cache1ast<true>,那么它也 可以使用 push back() s1ist< point, cache1ast<true>>s1;//使用元数据选项配置 sl push back(pl): //可以使用 push back() 622使用成员挂钩 基类挂钩是使用侵入式容器最简单的方式,但有的时候我们可能不想使用基类挂钩,因 为这种继承关系可能不是我们想要的。这时可以使用成员挂钩,把挂钩作为自有类的一个 Boost程序库探秘——深度解析C++准标准库(第2版) 260 第6章侵入式容器 public成员: class point /不使用基类挂钩 public: //同前 slist member hook<>m hook; //成员挂钩,缺省配置 侵入式容器在容纳使用成员挂钩的类时要多做一些工作,需要用一个 member hook< 配置选项,告诉容器成员挂钩的类型和挂钩变量名: slist<pointr //元素类型 member hook <point, //成员挂钩选项 slist member hook<>,&point:: m hook>, /成员挂钩变量 sli 使用成员挂钩的完整代码如下,这里我们还使用了指针容器来动态创建对象: #include <hoost/ptr container/ptr vector hpp> #include <hoost/assign/ptr list of hpp> include <boost/intrusive/slist hpp> using namespace boost: : intrusive using namespace boost int main() using namespace boost: assign: // assign名字空间 ptr vector<point> vec //指针容器 ptr list of<point>()(2, 2)(3,3)i /使用 assign库初始化 typedef member hook< point, slist member hook<>,//使用成员挂钩 typedef spoint: m hook> member option; //简化类型定义 slist<point, member option> sl; //单链表侵入式容器 BOOST REVERSE FOREACH (point& p, vec) //逆序遍历指针容器 sI push front (p)i //使用 push front() assert(sl size()==3)i ①实际上这相当于我们手工处理了成员变量指针类型,分解出类类型和成员变量类型,因为编译器不具备 从成员变量指针中推导出这些类型的能力,算是个“无奈之举”吧。 Boost程序库探秘——深度解析C++准标准库(第2版)

...展开详情
试读 50P Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)
img
wishernzl

关注 私信 TA的资源

上传资源赚积分,得勋章
    最新推荐
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版) 9积分/C币 立即下载
    1/50
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第1页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第2页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第3页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第4页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第5页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第6页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第7页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第8页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第9页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第10页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第11页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第12页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第13页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第14页
    Boost程序库探秘 深度解析C++准标准库(251-300) (第二版)第15页

    试读已结束,剩余35页未读...

    9积分/C币 立即下载 >