推荐序
最近一年,我电话面试了数十位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源码并不轻松,需要使用者下一番功夫。如果使用者沉迷于这些有趣的底层细节而忘了原本要解决什么问题,恐怕就舍本逐末了。
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的大部分常用内容,能让读者迅速了解Boost,并从中找到自己需要的部分。拿到这本书之后,我有粗有细地阅读了一遍,总体来看,作者水平很高,也相当务实,作者对C 和Boost的理解与运用很到位,我从这本书中学到了不少新知识。为此,我乐于向希望学习Boost程序库的开发者推荐这本靠谱的书。
须知“功不唐捐”,作为一名现代C 程序员,在Boost上投入的精力定能获得回报。
陈硕
《代码大全》译者之一
中国香港
十周年纪念·特别序言
儿时的友情纯真得无忧无虑,长大后的友情真挚得催人泪下,朋友间说不出谢字,我们之间只剩一颗炽热的心。怀念那时每一场“战役”,那屋后白雪皑皑的“堡垒”,那游戏机前的等待。感谢那一只手套,那一个微笑,我们拥有着共同的岁月和青春,叫一声朋友,这个年代,这份友情,没有什么比你更加让我自豪。我的朋友!因为有你,童年才值得回味。就让我们紧握友情,幸福走过……
——小学同学 岳大海
罗剑锋是我的“发小”,那时的他是班级、学校的骄傲,是名副其实的“学霸”,现在的他则是我们这些玩伴的骄傲。他过着让别人羡慕的人生,但我们却知道,这是他一步一个脚印,一步一滴汗水走过来的。他所有的成就我们都有目共睹,儿时的种种经历虽已过许久,却记忆犹新。
他和我们一起疯过,笑过,闹过,奋斗过,拼搏过,那些回忆让人更珍惜我们单纯的情谊。有种惦记疏淡,却很甘甜;有种问候平常,却很温暖;有种信任无言,却最亲切;有种友谊清澈,却最长远。
——小学同学 王峰
我跟老罗是从小认识的,他比我高很多年级,我上初中的时候他好像就参加完高考了。
那时候他一直是我们林场中“别人家的孩子”,不得不说老罗对我的影响挺大的,因为我的父母总教育我打游戏会耽误学习,但是我发现老罗游戏打得好,也没耽误学习啊。所以我对家长的这条教育一直是不屑的。但是后来我发现我错了,因为“既擅长打游戏又不耽误学习”不是适用于所有人的。
老罗打RPG/SLG游戏是高手,他很有耐心,一个游戏通关几遍是常事,然后还会鼓动你多尝试几次,不知道是不是想让他这个“游戏厅老板”多赚点钱。但是他不擅长对战类游戏,在这方面他常常是我的手下败将。
老罗喜欢看书、写书、看电影,当时我很难理解,书有什么可看的,不如多打几盘游戏。问题是他看书看多了,还要写书,这种表现太让人“气愤”了,有时恨得“咬牙切齿”,你说至于么,都是打游戏的人,何必甩我们几条街。看电影也是,看点中国的啊,全是国外的,不知道从哪里整得那么多碟片,我看都看不懂,就记得有部电影里面有个人躲子弹有点厉害。
不说了,人家现在日子过得好,说多了显得我嫉妒他。
——小学同学 袁斌
时光荏苒,岁月如梭,想想认识罗儿(我喜欢这么叫他)已有三十年了,岁月真是把杀猪刀啊!初一入学第一天我们相识的场景还历历在目,如今我的儿子都已经很大了,想想这三十年,我们是真正的好“基友”:初中、高中我们在同一个班,大学我们分开了一段时间,但大学毕业后,我们又来到同一个城市,还在同一个区。罗儿不仅是我的朋友,更是我的兄弟。
罗儿是一个很踏实的人,他做任何事情都会做到极致,我最佩服他这一点。同样是玩游戏,他不仅能通关还能给杂志社写攻略赚稿费。同样是学习,从初一开始,我们这届就没见过别人能考第一,无论你是从哪儿转学过来的,无论题有多难,他一直是我们这届学生中名副其实的“学霸”。我现在还经常用罗儿的事例教育我儿子:“你罗叔叔当年就是这么学的!”
罗儿是一个爱好广泛的人,喜欢迈克尔·杰克逊、郑智化的音乐,还喜欢看《七龙珠》《幽游白书》等漫画。刚开始我都不知道这些是什么,在他的带动下开始接触,也慢慢喜欢。我们总在一起讨论漫画情节,或者在晚自习回家的路上大声唱歌,我对这些事物仅仅是喜欢,但罗儿把漫画插页画出来还集成册,这就厉害了!
最后说到罗儿的书,其实我一点也不懂,真的是“天书”,但是我相信我兄弟,他的书准没错,就像他的人一样!
——中学同学 时吉斌
岁月在不知不觉间潺潺流淌,带走了三十载的光阴,罗剑锋中学时的样子仿佛还氤氲在我的眼前。
毕业后,昔日同窗的情谊没有因为距离增长而愈见稀薄,反而因为时间的酝酿而更加珍贵。闲暇或偶尔出差去北京时,我会与老友点我们最爱的烤鸭,共叙闲话,聊聊儿女,每每都会生出于繁忙生活中偷得闲生的轻松之感。
三十年后的今天,老同学说让我帮他的书写个序,一时感慨良多,说起来这还是我第一次为书写序。还记得初中时罗剑锋一直是班级第一,而我偏是那万年第二,少年的意气当然不允许这样,可惜超过他始终是这些年我未竟的心愿。他始终是我们中学同学的骄傲,记忆中他的眼睛总是那么炯炯有神,好像总有用不完的精力,没有解决不了的难题,在学习