Boost程序库完全开发指南——深入C++”准”标准库(第4版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-10 22:21:43

点击下载

作者:罗剑锋

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Boost程序库完全开发指南——深入C++”准”标准库(第4版)

Boost程序库完全开发指南——深入C++”准”标准库(第4版)试读:

内容简介

Boost是一个功能强大、构造精巧、跨平台、开源并且完全免费的C++程序库,有着“C++‘准’标准库”的美誉。

Boost由C++标准委员会部分成员所设立的Boost社区开发并维护,使用了许多现代C++编程技术,内容涵盖字符串处理、正则表达式、容器与数据结构、并发编程、函数式编程、泛型编程、设计模式实现等许多领域,极大地丰富了C++的功能和表现力,能够使C++软件开发更加简捷、优雅、灵活和高效。

本书基于2017年4月发布的Boost1.64版,介绍了其中的所有140余个库,并且结合C++11/14/17标准详细、深入地讲解了其中数十个库,同时实现了若干颇具实用价值的工具类和函数,可帮助读者迅速地理解、掌握Boost的用法并应用于实际的开发工作。

本书内容丰富、结构严谨、详略得当、讲解透彻,带领读者领略了 C++的最新前沿技术,相信会是每位C++程序员的必备工具书。

未经许可,不得以任何方式复制或抄袭本书之部分或全部内容。

版权所有,侵权必究。

图书在版编目(CIP)数据

Boost程序库完全开发指南:深入C++“准”标准库/罗剑锋著. —4版. —北京:电子工业出版社,2017.10

ISBN 978-7-121-32460-4

Ⅰ. ①B… Ⅱ. ①罗… Ⅲ. ①C++语言-程序设计-指南 Ⅳ. ①TP312.8-62

中国版本图书馆CIP数据核字(2017)第195365号

责任编辑:安娜

印刷:三河市鑫金马印装有限公司

装订:三河市鑫金马印装有限公司

出版发行:电子工业出版社

北京市海淀区万寿路173信箱 邮编 100036

开本:787×980 1/16 印张:36.75 字数:812千字

版次:2017年10月第1版

印次:2017年10月第1次印刷

印数:2500册 定价:99.00元

凡所购买电子工业出版社图书有缺损问题,请向购买书店调换。若书店售缺,请与本社发行部联系,联系及邮购电话:(010)88254888,88258888。

质量投诉请发邮件至zlts@phei.com.cn,盗版侵权举报请发邮件至dbqq@phei.com.cn。

本书咨询联系方式:010-51260888-819,faq@phei.com.cn。推荐序

最近一年我电话面试了数十位C++应聘者,惯用的暖场问题是“工作中使用过STL的哪些组件?用过Boost的哪些组件?”得到的答案大多集中在vector、map和shared_ptr。如果对方是在校学生,我一般会问问vector或map的内部实现、各种操作的复杂度,以及迭代器失效的可能场景。如果是有经验的程序员,我还会追问shared_ptr的线程安全性、循环引用的后果及如何避免、weak_ptr的作用等。如果这些都回答得不错,进一步还可以问问如何实现线程安全的引用计数,如何定制删除动作等。这些问题让我能迅速地判别对方的C++水平。

我之所以在面试时问到 Boost,是因为其中的许多组件确实可以用于编写可维护的产品代码。Boost 包含近百个程序库,其中不乏具有工程实用价值的佳品。每个人口味与技术背景不一样,对 Boost 的取舍也不一样。就我的个人经验而言,首先可以使用绝对无害的库,例如noncopyable、scoped_ptr、static_assert等,这些库的学习和使用都比较简单,容易入手。其次,有些功能自己实现起来并不困难,正好Boost里提供了现成的代码,那就不妨一用,比如date_time和circular_buffer等。然后,在新项目中,对于消息传递和资源管理可以考虑采用更加现代的方式,例如用 function/bind 在某些情况下代替虚函数作为库的回调接口、借助 shared_ptr 实现线程安全的对象回调等。这二者会影响整个程序的设计思路与风格,需要通盘考虑,如果正确使用智能指针,在现代C++程序里一般不需要出现delete语句。最后,对某些性能不佳的库保持警惕,比如 lexical_cast。总之,在项目组成员人人都能理解并运用的基础上,适当引入现成的Boost组件,以减少重复劳动,提高生产力。

Boost是一个宝库,其中既有可以直接拿来用的代码,也有值得借鉴的设计思路。试举一例:正则表达式库regex对线程安全的处理。

早期的RegEx类不是线程安全的,它把“正则表达式”和“匹配动作”放到了一个类里边。由于有可变数据,RegEx 的对象不能跨线程使用。如今的 RegEx 明确地区分了不可变(immutable)与可变(mutable)的数据,前者可以安全地跨线程共享,后者则不行。比如正则表达式本身(basic_regex)与一次匹配的结果(match_results)是不可变的;而匹配动作本身(match_regex)涉及状态更新,是可变的,于是用可重入的函数将其封装起来,不让这些数据泄露给别的线程。正是由于做了这样合理的区分,RegEx在正常使用时就不必加锁。

Donald Knuth在Coders at Work一书里表达了这样一个观点:如果程序员的工作就是摆弄参数去调用现成的库,而不知道这些库是如何实现的,那么这份职业就没啥乐趣可言。换句话说,固然我们强调工作中不要重新发明轮子,但是作为一个合格的程序员,应该具备自制轮子的能力。非不能也,是不为也。

C/C++语言的一大特点是其标准库可以用语言自身实现。C标准库的strlen、strcpy、strcmp系列函数是教学与练习的好题材,C++标准库的complex、string、vector则是类、资源管理、模板编程的绝佳示范。在深入了解 STL 的实现之后,运用 STL 自然手到擒来,并能自动避免一些错误和低效的用法。

对于Boost也是如此,为了消除使用时的疑虑,为了用得更顺手,有时我们需要适当了解其内部实现,甚至编写简化版用做对比验证。但是由于Boost代码用到了日常应用程序开发中不常见的高级语法和技巧,并且为了跨多个平台和编译器而大量使用了预处理宏,阅读Boost源码并不轻松惬意,需要下一番工夫。另一方面,如果沉迷于这些有趣的底层细节而忘了原本要解决什么问题,恐怕就舍本逐末了。

Boost中的很多库是按泛型编程的范式来设计的,对于熟悉面向对象编程的人而言,或许面临一个思路的转变。比如,你得熟悉泛型编程的那套术语,如 concept、model、refinement,才容易读懂 Boost.Threads 文档中关于各种锁的描述。我想,对于熟悉STL设计理念的人而言,这不是什么大问题。

在某些领域,Boost不是唯一的选择,也不一定是最好的选择。比如,要生成公式化的源代码,我会首选用脚本语言写一小段代码生成程序,而不用 Boost.Preprocessor;要在C++程序中嵌入领域特定语言,我会首选用Lua或其他语言解释器,而不用Boost.Proto;要用 C++程序解析上下文无关文法,我会首选用 ANTLR来定义词法与语法规则并生成解析器(parser),而不用Boost.Spirit。总之,使用Boost时心态要平和,别较劲去改造C++语言。把它有助于提高生产力的那部分功能充分发挥出来,让项目从中受益才是关键。

要学习Boost,除了阅读其官方网站的文档、示例与源码外,最好能有一本比较全面的中文书在手边随时翻阅。对于不谙英文的开发者,这更是可幸之至。您手上这本《Boost 程序库完全开发指南》是很好的使用指南与参考手册。作者由浅入深地介绍了Boost的大部分常用内容,能让读者迅速了解Boost,并从中找到自己需要的部分。拿到这本书稿之后,我有粗有细地阅读了一遍,总体来看,作者水平很高,也相当务实,对 C++和 Boost 的理解与运用很到位,我从这本书学到了不少新知识。为此,我乐于向希望学习Boost程序库的开发者推荐这本靠谱的书。

须知“功不唐捐”,作为一名现代C++程序员,在Boost上投入的精力定能获得回报。

陈硕《代码大全》译者之一

中国·香港第4版前言

本书初版面市至今已过去了七年的时间,这些年里我一直在持续关注 Boost/C++的发展和动态,及时更新维护这本书已经成为了我的一种习惯甚至是一种生活方式。随着C++17的发布,编写新版的工作也就自然而然地提上了日程。

这次修订的过程也是对自己的一个反省:感觉前几版有点“贪大求全”,做的是“加法”,恨不得把 Boost/C++相关的所有细节都列出来,未免显得有些啰唆,所以这次的第 4 版就冷静了些,开始做“减法”。在修正笔误、微调代码格式、更新 date_time、test 等库之外,删去了几个实际价值不是很高的组件,例如scoped_array、swap、tokenizer等,希望精简后阅读起来能够更加顺畅,更方便学习研究。

不过也有声音反映作者对本书的修订过于“武断”“任性”,觉得删除的内容看不到了比较可惜。为了弥补新版导致的“缺憾”,我把之前删掉的章节都做成了 PDF 文件,放到了GitHub上,感兴趣的读者可以自行下载查阅。

祝您阅读愉快,愿我们C++20时再相见!

罗剑锋

2017年7月17日 于 北京 亚运村第1版前言

屈指算来,接触C++语言至今已经有十余个年头了。回首往事,不禁感慨良多。

缘起

1996年我上大学最开始学的是Pascal,不得不说,Pascal严谨的程序风格确实很适合作为一门教学语言,然而用于实际开发就不那么合适了(直到出现Delphi)。由于当时学校并未开设C语言课程,因此在Pascal课程结束后我就买书自学C/C++语言,并在次年报名计算机软件专业技术资格和水平考试,靠着一点点编程和考试的“天分”获得了高级程序员资质(当年很热衷考级考证,后来就“淡定”多了)。虽然有了资格证,但我仍然算是个C++的初学者,对于C++的认识还处于C的面向过程和简单的基于对象层次上。

新千年伊始我考入了北京理工大学就读研究生,因为跟导师做项目开始接触STL与C++标准库,大概是2005年从1.33版结识了Boost,这才真正领略了C++的精髓。那段时期Java和C#正在国内大行其道,C++则势单力薄,有关STL和C++标准的技术书籍寥寥无几,而讲解Boost的书更是为零,故对Boost的学习基本只能靠自己的摸索与实践。好在Boost自带的文档相当丰富(尽管看全英文的资料十分辛苦),而且源码也写得比较清晰规范,在熟悉了STL的基础上学习Boost倒也并不算太难。

但Boost的一个最大的特点就是“庞大”,功能组件众多,要想把它全部装进脑子里融会贯通基本上是不可能的,使用时需要经常查阅英文文档,相当麻烦。因此,在学习的过程中,我逐渐产生了编写学习笔记的想法。一开始只是一个简单的纯文本文件,记录了一些使用经验的片断,随着积累不断增加,纯文本形式已经不能满足知识整理的需求了,于是我又把这些文字迁移到了Word文档里,把使用经验分类编目,进行较系统的归纳梳理。慢慢地,这份学习笔记居然有了上万字的规模,成为了一份很好的Boost备忘参考,在日常的开发工作中给了我很大的帮助—就像《设计模式》一书中所说的那样,捕获了很多使用 Boost解决问题的实践经验,避免了重复发现。不过,这份资料一直仅限于我个人使用,属于“自娱自乐”的作品,从未示人。

时间一晃到了2010年1月份的某天夜里,不知道是什么原因我忽然失眠了,躺在床上翻来覆去怎么也睡不着。突然,一个念头闯入了脑海:把Boost开发经验整理出版吧,让更多人能够分享这些知识,正所谓“独乐乐,与众乐乐,孰乐?”这个大胆的想法的出现让我那天的失眠又延长了几个小时—关于书的各种构想在头脑中“肆虐横行”。

随后的几天里我就把这个想法付诸行动了,虽然以前也写过并发表很多文章,也在网上印刷了几本个人文集,但出版正式的书还是第一次。在把学习笔记进一步整理完善,编写出较完整的结构和一个样章后,我就开始联系出版社了。当初并没有多大的信心,毕竟我这个作者名不见经传,也没有什么资历、背景和名气(而且还是个“网盲”,从未跟随潮流开个人博客)。很幸运,发出的第一个 E-mail 就是电子工业出版社,而且编辑也在第一时间回复了我,这才给了我以持续写作完成全书的动力。

写作过程中我也进一步加深了对Boost的认识,澄清了许多原来未曾注意到的细节。原本只打算写20万字左右、三百多页,但写到中途才发现Boost库的博大精深远非当初的理解,也意识到了自己当初学习的肤浅。历经了近半年近乎不眠不休的努力,最终呈现给读者的是这本厚达500多页的图书,文字量是最初学习笔记的数十倍,内容也翔实丰满了很多—达成这个结果,我个人可以说是问心无愧了。

C++与Boost

C++较Java和C#等语言的一个最大不同在于它并非是由某个公司或个人把持的,它的真正发展动力来自于广大程序员。Boost 就是这样的一个典范,它成功地填补了从 C++98到C++0X这“失落的十年”间的空白,在竞争对手Java和C#不断更新版本新增特性的时候以库的形式极大地增强了C++的能力,使C++不至于因为标准规范的滞后而落后于时代,而且 Boost 还深层次地挖掘了 C++的潜力,开创了泛型编程、模板元编程、函数式编程等崭新的境界。

就个人来说,我比较喜欢的 Boost版本有两个,分别是 1.35和 1.39。1.35版增加了 asio、bimap、circular_buffer等许多重要组件,而 1.39版则增加了 signals2库,这两个版本都在我的工作用机上停留了相当长的时间。落笔之时,Boost已经更新到了1.43版,成长为一个相当完善、全面、强大的C++程序库。可以毫不夸张地说,现在的C++程序员,如果不熟悉Boost,那么至少丧失了一半使用C++的好处,同时会多耗费数倍的开发精力和时间。

随着 C++0X 标准的即将来临,Boost 程序库的发展也出现了加速的趋势,由原来间隔数月不定期更新版本,改为定期(每3个月左右)发布新版本,而且每个新版本都会包含大量极有价值的更新内容。因此,希望读者在阅读本书时及时访问Boost的官网(http:://www.boost.org),以便获取最新的版本。

感谢读者选择本书,再说一句真心的“套话”(笑):限于作者水平有限,书中错漏在所难免,敬请读者原谅、指正。

致谢

首先我要感谢整个C++群体,特别是:C++语言的发明者Bjarne Stroustrup博士—他给我们带来了美妙的C++;然后是Alexander Stepanov和C++标准委员会—他们把STL引入了C++,开创了C++的现代编程风格;以及Beman G.Dawes、Boost程序库的所有作者和Boost社区—他们为我们奉献了如此高水准的程序库。

其次我要感谢电子工业出版社博文视点公司,他们给了我这个把自己的开发经验出版成书的机会,在把潦草的个人学习笔记变成正式图书的过程中他们付出了艰辛的努力。还要感谢陈硕先生,他审阅了本书的部分手稿,提出了很多有价值的参考意见,并慨然为本书撰写序言。

接下来我要感谢我的家人:感谢我的父母和弟弟,他们永远是我生命中最重要的人;感谢我的妻子,她自始至终都支持我的写作,并担负了大部分照顾孩子的家务(虽然偶有怨言);还要对已满一岁半的女儿说声抱歉,为了写作本书,我已经牺牲了很多陪她玩耍的时间。

我还要感谢黄美华、冯薇、戚天龙、罗玉震、颜静、陈刚、张秋香、缪泽波等同事,长期的共事令我们建立了深厚的友谊。对后两位同事致以特别的感谢,他们对完成本书提供了大力的支持和帮助。

最后,感谢多年以来的好友岳大海、时吉斌、王峰,感谢我的中学老师邓英、杜爱芹、练鑫云、陈静,感谢我的研究生导师贾云得,以及所有在我成长过程中曾经给予我关心和帮助的朋友们!

罗剑锋

2010年6月7日 于 北京 王府井第0章 导读0.1 关于本书

C++是一种伟大的编程语言,某种程度上它甚至超越了编程语言的境界而升华为一种哲学。

C++又是一种多范式、可扩展的编程语言,支持多种编程风格—基于过程、基于对象、面向对象、函数式、泛型、模板元、自动机,非常自由灵活,易学难精,在不同编程风格间切换时必须小心谨慎以避免失误。

C++标准中出现的STL(标准模板库)极大地改变了C++程序员的编程思维,使“泛型”成为了 21 世纪以来程序开发界最流行的词汇之一。而 C++标准委员会成员所设立的 Boost社区和开发的Boost程序库,更将“泛型”等现代C++编程方法发挥到了极致。

Boost 程序库代表了目前 C++语言最新最前沿的技术,内容博大精深,丝毫不逊于经典的STL,但同时也令很多人难以摸清门路,不得登堂入室而一窥究竟。有鉴于此,作者根据多年在实际开发中使用Boost库的经验并结合最新的C++标准编写了本书,想为广大C++程序员了解C++的最新技术进展尽一份自己的力量。

本书的定位是“指南”(Guide、Introduction),而不是技术手册(Reference)或者使用说明(Manual),能够解答90%但不是所有Boost库相关的问题。但作者尽量做到让本书接近一本参考手册,使读者在阅读时能够脱离计算机,不至于频繁使用鼠标和键盘查询在线帮助或者源代码。0.2 读者对象

本书适合有一定C++基础的读者。

阅读本书需要有一定的C++知识,基本要求是熟悉面向对象编程技术,如封装、继承、多态,此外还要理解名字空间、异常、模板[1]、泛型编程等高级特性(但不必非常深入),最好还能够了解设计模式和C++标准库提供的容器、算法等各种组件。

如果读者是 C++初学者或还不具备以上所列的知识,建议先阅读附录 A 推荐书目里的技术书籍,然后再学习本书。如果手头刚好有推荐书目中的一本或两本,则可以一边翻阅这些书籍,一边学习本书。

总之,无论读者是C++哪一层次的用户,现在或将来本书都会给您带来帮助。0.3 术语与风格

本节列出了书中经常用到的专业术语和编程风格,以期与读者获得阅读的共识。

Boost 库并不是一个单一、平面化的程序库,而是有着复杂的内部结构,每个“库”可能是由其他许多更小的“库”组成的。因此,本书把程序库中所有组成部分统称为“组件”,“库”(Library)与“组件”(Compoment)这两个术语有时会通用。

namespace 这个术语有译作“命名空间”、“名称空间”、“名字空间”,本书称作“名字空间”。这只是作者个人习惯而已,如果在阅读过程中给读者造成了小小的困扰,还请谅解。

在使用template定义模板类或者模板函数时,本书统一使用typename而不是常见的class,因为 typename 能够更清楚地向代码阅读者表明这是一个类型参数,而不一定是一个类(class)。但例外的是书中列出Boost源代码,会尽量保持其原始形式。

在命名函数或者类时,本书遵循C++标准库和Boost的惯例,均采用小写形式,单词间以下画线分隔,如 demo_class、rand_bytes(),但并不要求读者也必须遵循这种命名方式,通常自己编写的类使用大写字母开头的单词命名会更好。

在 for 循环递增变量、指针或者迭代器对象的时候,本书统一使用++操作符的前置用法(++i),而不是后置用法(i++),因为前者不需要返回一个临时对象,执行效率更高。“未定义行为”一词经常用来指代某些操作可能导致的不正确结果,如使用已失效的迭代器、错误地使用指针,等等。对于“未定义行为”的一个较好(但不太精确)的定义是:程序在开发人员面前运行正常,在测试人员面前运行正常,但在老板或者最终用户面前运行时崩溃了。读者应当小心并尽量避免“未定义行为”,它是代码中的“定时炸弹”,如果它在调试的过程中爆炸了,那通常是最好的结果,因为它明确地告诉了我们代码存在问题。0.4 语言标准

现在 C++有四个版本的国际标准:C++98、C++11、C++14 和 C++17[2],本书主要使用C++11(ISO/IEC 14882:2011),不含数字标识的“C++标准”一词通常就是指这个标准,但在涉及C++某些语言特性时可能会明确标明具体的版本,有时还会以“C++11.x.y.z”的形式标明所引用C++标准文档的章节号。

书中使用较多的新语言特性有四个:

■ nullptr:强类型的空指针;

■ auto/decltype:自动推导表达式类型;

■ for:基于范围的新式循环,形式更加优雅;

■ lambda表达式:又称闭包(closure),能够非常便捷地定义函数对象,通常的形式是[](...){...},其中[]是捕获列表,()是函数参数,{}是函数体。

C++标准中定义的函数库本书称为“C++标准库”或者“STL”,但严格意义上STL与标准库并不等价,STL只是标准库中的一个(很大的)子集,这么称呼有时候只是为了行文上的方便。

一般情况下使用C++标准库都必须包含相应的头文件并且加上“using namespace std”语句,但标准库已经成为了C++软件开发的基础设施,应用得非常频繁,因此书中的代码示例片断一般会将之略去。但有的情况下为了特别强调,会加上 std 名字空间前缀,如 std::vector。读者可以认为书中所有代码都默认包含了如下的头文件:

为使读者对C++标准能够有更多的了解,作者编写了一份简要介绍,作为本书附录供参考。0.5 本书的结构

Boost库组件繁多,相互关联也较多,如何排列其顺序是作者面临的一个颇为棘手的问题。

Boost 官方提供了两种基本方式:一种是按照组件的字母顺序,另一种是按照功能用途分类顺序,但这两种方式都不是组织本书结构的最佳手法。经反复考量,作者决定以难易度和实用程度对 Boost 库组件分类排序,采用由浅入深循序渐进的方式,先介绍较简单易用且实用程度高的库,然后逐步深入,介绍用法复杂的库,以期帮助读者尽快掌握 Boost的使用方法。

对于每个Boost组件,本书通常首先简要介绍其功能,然后说明其头文件和编译方法(如果需要编译的话),列出类的声明概要,再使用例子讲解详细用法和注意事项,涉及其他Boost库组件时则以交叉引用的方式指明参考章节,最后是对该库的总结。

本书共分16章,各章的内容简介如下:

■ 第1章:总论

简要介绍Boost的历史、特点和获取方式,以及本书的开发环境和如何编译安装Boost。

■ 第2章至第13章

第2章至第13章分门别类、由浅入深地介绍Boost库的各个组件,占据了本书的大部分篇幅,也是读者需要仔细阅读的内容。其中既包括如timer、noncopyable等简单的小工具,也包括test、thread、asio等用法复杂且功能强大的组件,Boost 1.64版全部140余个库在本书中都可以找到阐述。

■ 第14章:设计模式

本章结合之前介绍的Boost库组件简要论述了推荐书目[1]中的23个设计模式和4个其他常用模式,以及 Boost 库使用这些设计模式的方法,从设计模式的抽象层次来加深理解Boost库。

■ 第15章:结束语

本章简单展望了 Boost 今后的发展,介绍其他可与 Boost 互为补充的开源 C/C++库,并对如何做一个好的程序员提出了自己的见解。

■ 附录

书末的附录也很有价值,列出了作者认为值得阅读的 C/C++经典书籍—它们也是作者编写本书时的案头必备参考资料,还有就是C++标准简述和编程经验谈。

这些内容被放在附录部分并不是因为它们不重要,而仅仅是因为它们与全书的主题关联不大,但很值得阅读,读者也许会从中发现一些很有用的东西。0.6 如何阅读本书

本书是一本介绍程序库的书籍,其中的很多组件是彼此独立的,所以在阅读完第0章(即本章)和第1章后,可以随意愿自由阅读其他章节。

读者既可以按照书的物理顺序循序渐进地逐页阅读,也可以查阅目录,然后直接跳到感兴趣的章节。不过对于大多数读者来说,作者还是推荐第一种方式,因为这可能会是学习效率更高、学习曲线更平滑的方式。

涉及编程语言,尤其是C++,书中不可避免地会出现大量的代码片断,有的还可能很长,希望读者阅读时能有足够的耐心。这些代码都是精心编制的范例,将会指导读者如何使用Boost编写正确、高效的代码。

阅读时还需要注意一点:本书并不包含 Boost 库的所有接口说明,如果在阅读过程中对某些地方有疑虑,请参考Boost说明文档或者直接阅读Boost实现代码。0.7 本书的源码

为了更好地方便读者利用本书学习研究Boost程序库,作者在GitHub网站上发布了书内所有示例程序的源代码,读者可以根据需要自取。[3]

本书源码的GitHub项目地址是:

那么,欢迎来到Boost的世界。

[1]模板类和模板函数一般形式是class_or_func<;T>;,例如vector<;int>;。<;>;在编程语言中通常被用于大小比较,因此其形式对于初学者很难接受,但这种形式具有良好的可读性,<;>;可以被读作英文of,比如vector<;int>;可以读作vector of int,清晰地表明了类/函数和它的模板类型的关系,这样可以减少一部分对尖括号的不适应感,作者经常这么做,读者也可以试一下,很有效。

[2]实际上还应该有一个C++03标准,但因为它与C++98的差异很小,故本书忽略之。

[3]有了GitHub,再也不需要“附赠光盘”了,笑。第1章 总论

Boost是一个功能强大、构造精巧、跨平台、开源并且完全免费的C++程序库。

本章将带领读者快速浏览 Boost 程序库,了解它的历史、组成和基本使用方式,并在Linux上搭建自己的开发环境,为之后的学习做准备。1.1 简介

1998年,Beman G.Dawes(C++标准委员会成员之一)发起倡议并建立了Boost社区,目的是向 C++程序员提供免费的、同行审查的、可移植的高质量 C++源程序库。Boost 强调程序库要与 C++标准库很好地共同工作,建立在“既有的实践”之上和提供参考实现,使得Boost 库可以适合最后的标准化。自创立以来,Boost 社区的工作已经取得了卓越的成果,C++标准库中有三分之二来自Boost库,而且将来还会有更多的库进入新标准。

C++三十余年的发展历史中产生了数不清的程序库,有影响力的也不计其数,然而没有一个能够与Boost相提并论,Boost有着与其他程序库无法比拟的优点:

■ 首先,许多Boost库的作者本身就是C++标准委员会成员,因此Boost天然成为了标准库的后备,负责向新标准输送组件,也使得 Boost 获得了“准”标准库的美誉[1]。

■ 其次,Boost独特的同行审查制度保证了每一个Boost库组件都经过了严格的审查和验证,使库具有很高的工业强度,甚至超过大多数商业产品的实现。Boost 采用了类似STL的编程范式,但却并没有STL那样晦涩难懂,代码格式优美清晰、易于阅读,而且附带丰富的说明文档—它既是一个程序库,同时也是一个很有价值的学习现代C++编程的范本。

■ 最后,Boost 的发布采用 Boost Software License,这是一个不同于 GPL、Apache 的非常宽松的许可证,允许库用户将 Boost 用于任何用途,既鼓励商业用途,也鼓励非商业用途。用户无须支付任何费用,不受任何限制,即可轻松享有Boost的全部功能。

本书内容基于Boost官方于2017年4月发布的1.64版,共包含140余个库/组件,分为25大类,涵盖字符串与文本处理、容器、迭代器、算法、图像处理、模板元编程、并发编程等许多领域—使用Boost,将大大增强C++的功能和表现力。

虽然本书主要讨论Boost 1.64版,但由于Boost库中的许多组件已经相当稳定,故书中的论述对1.64版之前和之后的版本也基本适用。1.1.1 获取方式

Boost提供源码形式的安装包,可以从Boost官方网站(http://www.boost.org)下载最新版本—本书使用的是 boost_1_64_0.tar.gz,把该文件解压缩到磁盘任意位置即可,例如:1.1.2 目录结构

Boost压缩包解开后有5万多个文件,占据近700MB的磁盘空间,但目录结构却很简洁清晰:

大多数情况下我们只需要关心 boost子目录,这里以头文件的形式分门别类存放了我们要使用的库代码:1.1.3 使用方式

Boost库大多数组件不需要编译链接,我们在自己的源码里直接包含头文件即可。例如,如果要使用 boost::tribool,只需要在 C++源文件中添加如下 include 语句(当然,接下来的代码可能还需要“using namespace boost;”):

细心的读者会发现,Boost库的头文件与我们平常所用的头文件(*.h)或C++标准库头文件(没有后缀名)不同,这正是Boost的独特之处。它把C++类的声明和实现都放在了一个文件中,而不是分成两个文件,也就是“.h+.cpp”,故文件的后缀是.hpp。[2]

剩下的少量库(如 chrono、date_time、program_options、test、thread 等)必须编译成静态库或者动态库,并在构建时指定链接选项才能使用。不过有个好消息,其中有的库不需要编译也可以使用部分或全部功能,而更好的消息是有的库已经有了不需要编译的替代品。1.2 开发环境

阅读本书和使用 Boost,读者需要一个能够较好地支持 C++标准的操作系统和编译器,之后才能编译和安装Boost程序库。1.2.1 操作系统和编译器

C++是一个大型语言,十分复杂。虽然C++98标准已经面世近二十年,C++11标准也已经出台六年多,但仍然有很多编译器未能实现C++的全部特性。

由于Boost大量使用了C++高级特性(如模板偏特化、ADL),因此不是所有的编译器都能够很好地支持Boost,并且每个组件对编译器的支持都不尽相同。虽然Boost已经针对平台和编译器的兼容性做了大量的工作,但仍有可能出现意外情况。随着 Boost版本的增长,某些过“老”的编译器(例如VC6&7、GCC3)和CPU已经不再被支持。

本书作者使用的操作系统是 Ubuntu 14.04.05(Linux 4.4.0),编译器使用自带的GCC 4.8.4(对C++11标准的支持较完善),所有代码均在这个开发环境中编译通过。[3]1.2.2 快捷安装

Linux 操作系统下安装 Boost 很容易,最简单省事的方法是在Boost解压缩后的目录下直接执行命令:

第一条命令bootstrap.sh是编译前的配置工作,第二条命令b2开始真正的编译并安装Boost。[4]

如果像上面这样不指定额外选项,Boost将编译release版本的库文件,把头文件安装到“/usr/local/include”,库文件安装到“/usr/local/lib”。1.2.3 完全安装

我们也可以完整编译Boost,使用buildtype选项指定编译类型(如不指定则默认使用release模式),在bootstrap.sh之后执行如下命令:

这样将开始对Boost的完整编译,安装所有调试版、发行版的静态库和动态库。1.2.4 定制安装

完整编译 Boost 费时费力,而且这些库并不可能在开发过程中全部用到,因此,Boost也允许用户自行选择要编译的库。

执行命令:

可查看所有必须编译才能使用的库。

在完全编译命令的基础上,使用--with 或者--without 选项可打开或者关闭某个库的编译,如:

将仅编译安装date_time库。

本书使用的安装命令是:

b2 和 bootstrap.sh 还有其他很多选项,如指定安装路径、指定 debug 或 release版等,读者可使用--help选项或者参考Boost文档以获得更多信息。1.2.5 编译验证

让我们来编写一个简单的Boost应用程序来验证开发环境。

头文件<;boost/version.hpp>;里有两个宏,定义了当前使用的Boost程序库版本号:

头文件<;boost/config.hpp>;里有三个宏:BOOST_PLATFORM、BOOST_COMPILER和BOOST_STDLIB,分别定义了当前的操作系统、编译器和标准库。

下面的代码就是我们与Boost的第一次接触:

然后使用g++编译:

程序的运行结果是:1.3 构建工具

在Linux上有很多C/C++的构建工具,最常用的是make,此外还有cmake、scons等,本书采用的是Boost自带的构建工具b2—boost build v2。它是专门为构建Boost这样复杂度的软件而开发的构建工具,功能强大却又灵活方便,无论什么规模的软件都可以轻松管理—我们已经在安装Boost时见识了它的威力。

本节仅对b2做简略介绍,它的更多功能和使用方式的讲解已经超出了本书的范围。1.3.1 安装方式

为了使用b2构建我们的应用,我们需要在安装Boost程序库后再安装b2程序。

在Boost解压缩后的根目录下执行命令:

b2默认会被安装到“/usr/local/bin/”目录下。1.3.2 构建脚本

和 make 等构建工具一样,b2 也使用文本格式的构建脚本来管理代码,通常的名字是jamfile 或 Jamfile。此外 b2 还有一个特殊的 jamroot 文件,它需要放在整个项目的根目录下,用于管理项目树,定义整个项目的构建设置。

例如,本书源代码目录结构是:

jamroot 文件一般定义整个项目里通用的编译参数、包含路径等设置,避免每个子目录里的jamfile重复定义。对于Linux+GCC来说,常用的配置可以是:1.3.3 构建语言

b2使用的构建语言称为bjam,它是一个解释型语言,拥有完整的语法定义,包括变量、分支、循环语句、函数甚至还有类,如果读者熟悉 shell、awk 等脚本语言就会发现它们之间有很多相似之处。

完整地讲解 bjam 语言将耗费大量篇幅,这里仅介绍一些最常用的构建指令(实际上是bjam语言里的函数调用),对比make等同类工具可以看到语法非常简洁。

构建目标程序e,使用源码xxx.cpp、yyy.cpp和库zzz:

构建目标t,并且在编译后自动运行,通常用于单元测试:

定义链接库zzz,它依赖于depend_libs:

需要特别注意的一点:bjam 是基于 token 的语言,使用空格、tab 等空白字符来区分语法元素,不仅是单词,即使是“:”、“;”这样的标点符号前后也必须要有空格,否则bjam会无法识别标点,导致奇怪的语法错误。

下面的语句里“:”“;”与前面的单词连在了一起,是一个典型的错误例子:1.3.4 构建命令

b2实际上是bjam语言的解释器,它查找当前目录下的jamfile,并向上查找jamroot,解释执行其中的bjam语句,最终完成软件的构建。

常用的b2命令行参数如下:

通常我们直接执行b2就可以完成构建工作,它将构建jamfile里的所有目标,就像make all一样。1.4 总结

本章可以说是比赛开始前的“热身运动”,叙述了Boost的历史和特点,然后简要介绍了本书使用的开发环境以及编译安装Boost程序库和构建工具b2,希望读者能够借“他山之石”顺利搭建自己的开发环境。

如果一切准备就绪,接下来就让我们正式开始学习Boost。

[1]随着C++11/14标准的发布,Boost正逐渐向新标准靠拢,趋向于成为一个跨标准的“超级标准库”。

[2]之所以这么做当然是有理由的。首先就是与普通的C头文件(*.h)区分,另一个很重要的原因就是使Boost库不需要预先编译,直接引入程序员的工程即可编译链接,方便了库的使用。Java、C#、PHP、Python程序员应该对这种代码文件形式很熟悉,这几种语言都是在一个文件中编写所有代码。

[3]对于使用其他开发环境的读者只能说抱歉了,作者不能保证书中的脚本或代码能够百分之百正确运行。请参考Boost说明文档查看对您正在使用的平台和编译器的支持情况。

[4]得益于摩尔定律,现在Boost库编译所需要的时间和空间都已经大大缩减了,在目前主流级别CPU上只需要半小时左右,而在以前则需要数个小时。第2章 时间与日期

C++一直以来缺乏对时间和日期的处理能力,而时间和日期又是现实生活中经常遇到的,C++程序员不得不求助于C,使用笨拙的结构和函数。无法忍受这一情形的程序员则手工构造了自己的实现以满足开发所需,可以想象,有无数的程序员在这方面重复了大量的工作。

而现在,Boost使用timer、date_time和chrono完美地解决了这个问题。

本章介绍timer和date_time,而chrono库因为与操作系统联系较密切,将在第10章讲解。2.1 timer库概述

timer 是一个很小的库,提供简易的度量时间和进度显示功能,可以用于性能测试等需要计时的任务,对于大多数的情况它足够用。

Boost1.48版以后的timer库由两个组件组成:早期的timer(V1)和新的cpu_timer (V2),前者使用的是标准C/C++库函数,而后者则基于chrono库使用操作系统的API,计时精度更高。V1版的timer组件计时精度低,但对于Boost初学者来说还是具有一定的学习价值,故本章介绍这个timer组件,而cpu_timer则放在10.3节介绍。

timer(V1)库包含三个小组件,分别是:计时器timer、progress_timer和进度指示器progress_display,以下将分别详述。2.2 timer

timer 类可以测量时间的流逝,是一个小型的计时器,提供毫秒级别的计时精度和操作函数,供程序员手工控制使用,就像是个方便的秒表。

timer位于名字空间boost,需要包含头文件<;boost/timer.hpp>;,即:2.2.1 用法

让我们通过一段示例代码来看一下如何使用timer。[1]

上面的代码基本说明了timer的接口。timer对象一旦被声明,它的构造函数就“启动”了计时工作,之后就可以随时用elapsed()函数简单地测量自对象创建后所流逝的时间。成员函数elapsed_min()返回timer测量时间的最小精度,elapsed_max()返回timer能够测量的最大时间范围,两者的单位都是秒。

程序的输出如下:2.2.2 类摘要

timer 类非常小,全部实现包括所有注释也不过 70 余行,真正的实现代码则只有不到20行。作为我们学习的第一个Boost组件,值得把源码全部列出来仔细研究:

timer的计时使用了标准库头文件<;ctime>;里的std::clock()函数,它返回自进程启动以来的clock数,每秒的clock数则由宏CLOCKS_PER_SEC定义。[2]

timer 的构造函数记录当前的 clock 数作为计时起点,保存在私有成员变量_start_time 中。每当调用 elapsed()时就获取此时的 clock 数,减去计时起点_start_time,再除以 CLOCKS_PER_SEC获得以秒为单位的已经流逝的时间。如果调用函数 restart(),则重置_start_time重新开始计时。

函数 elapsed_min()返回 timer能够测量的最小时间单位,是 CLOCKS_PER_SEC的倒数。函数elapsed_max()使用了标准库的数值极限类numeric_limits,获得clock_t类型的最大值,采用类似elapsed()的方式计算可能的最大时间范围。

timer没有定义析构函数,这样做是正确且安全的。因为它仅有一个类型为clock_t的成员变量_start_time,故没有必要实现析构函数来特意“释放资源”(也无资源可供释放)。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载