第 1 章
新标准的诞生
从最初的代号C++0x到最终的名称C++11,C++的第二个真正意义上的标准姗姗来迟。可以想象,这个迟来的标准必定遭遇了许多的困难,而C++标准委员会应对这些困难的种种策略,则构成新的C++语言基因,我们可以从新的C++11标准中逐一体会。而客观上,这些基因也决定了C++11新特性的应用范畴。在本章中,我们会从设计思维和应用范畴两个维度对所有的C++11新特性进行分类,并依据这种分类对一些特性进行简单的介绍,从而一览C++11的全景。
1.1 曙光:C++11标准的诞生
1.1.1 C++11/C++0x(以及C11/C1x)—新标准诞生
2011年11月,在印第安纳州布卢明顿市,“八月印第安纳大学会议”(August Indiana University Meeting)缓缓落下帷幕。这次会议的结束,意味着长久以来以C++0x为代号的C++11标准终于被C++标准委员会批准通过。至此,C++新标准尘埃落定。从C++98标准通过的时间开始计算,C++标准委员会,即WG21,已经为新标准工作了11年多的时间。对于一个编程语言标准而言,11年显然是个非常长的时间。其间我们目睹了面向对象编程的盛极,也见证了泛型编程的风起云涌,还见证了C++后各种新的流行编程语言的诞生。不过在新世纪第二个10年的伊始,C++的标准终于二次来袭。
事实上,在2003年WG21曾经提交了一份技术勘误表(Technical Corrigendum,简称TC1)。这次修订使得C++03这个名字已经取代了C++98成为C++11之前的最新C++标准名称。不过由于TC1主要是对C++98标准中的漏洞进行修复,核心语言规则部分则没有改动,因此,人们还是习惯地把两个标准合称为C++98/03标准。
C++11是一种新语言的开端。虽然设计C++11的目的是为了要取代C++98/03,不过相比于C++03标准,C++11则带来了数量可观的变化,这包括了约140个新特性,以及对C++03标准中约600个缺陷的修正。因此,从这个角度看来C++11更像是从C++98/03中孕育出的一种新语言。正如当年C++98/03为C++引入了如异常处理、模板等许多让人耳目一新的新特性一样,C++11也通过大量新特性的引入,让C++的面貌焕然一新。这些全新的特性以及相应的全新的概念,都是我们要在本书中详细描述的。
1.1.2 什么是C++11/C++0x
C++0x是WG21计划取代C++98/03的新标准代号。这个代号还是在2003年的时候取的。当时委员会乐观地估计,新标准会在21世纪的第一个10年内完成。从当时看毕竟还有6年的时间,确实无论如何也该好了。不过2010新年钟声敲响的时候,WG21内部却还在为一些诸如哪些特性该放弃,哪些特性该被削减的议题而争论。于是所有人只好接受这个令人沮丧的事实:新标准没能准时发布。好在委员会成员保持着乐观的情绪,还常常相互开玩笑说,x不是一个0到9的十进制数,而应该是一个十六进制数,我们还可以有A、B、C、D、E、F。虽然这是个玩笑,但也有点认真的意思,如果需要,WG21会再使用“额外”的6年,在2015年之前完成标准。不过众所周知的,WG21“只”再花了两年时间就完成了C++11标准。
从表1-1中可以看到C++从诞生到最新通过的C++11标准的编年史。
图1-1比较了两个语言标准委员会(WG21,WG14)制定新标准的工作进程,其中一些重要时间点都标注了出来。
1.1.3 新C++语言的设计目标
如果读者已经学习过C++98/03,就可以发现C++98/03的设计目标如下:
这些特点使得面向对象编程和泛型编程在过去的10~20年内成为编程界的明星。不过从那时开始,C++的发展就不仅仅是靠学者的远见前瞻去推动的,有时也会借由一些“奇缘”而演进。比方说,C++模板就是这样一个“奇缘”。它使得C++近乎成为了一种函数式编程语言,而且还使得C++程序员拥有了模板元编程的能力。但是凡事有两面,C++98/03中的一些较为激进的特性,比如说动态异常处理、输出模板,现在回顾起来则是不太需要的。当然,这是由于我们有了“后见之明”,或者由于这些特性在新情况下不再适用,又或者它们影响了C++11的新特性的设计。因此一部分这样的特性已经被C++11弃用了。在附录B中我们会一一列出这些弃用的特性,并分析其被弃用的原因。
而C++11的整体设计目标如下:
我们可以分别解释一下。
首先,使C++成为更好的适用于系统开发及库开发的语言,意味着标准并不只是注重为某些特定的领域提供专业化功能,比如专门为Windows开发提供设计,或者专门为数值计算提供设计。标准希望的是使C++能够对各种系统的编程都作出贡献。
其次,使得C++更易于教学,则意味着C++11修复了许多令程序员不安的语言“毒瘤”。这样一来,C++语法显得更加一致化,新手使用起来也更容易上手,而且有了更好的语法保障。其实语言复杂也有复杂的好处,比如ROOTS、DEALII等一些复杂科学运算的算法,它们的作者非常喜爱泛型编程带来的灵活性,于是C++语言最复杂的部分正好满足了他们的需求。但是在这个世界上,新手总是远多于专家。而即使是专家,也常常只是精通自己的领域。因此语言不应该复杂到影响人们的学习。本书作者之一也是WG21中的一员,从结果上看,无论读者怎么看待C++11,委员会大多数人都认同C++11达成了易于教学这个目标(即使其中还存在着些看似严重的小缺陷)。
最后,则是语言的稳定性。经验告诉我们,伟大的编程语言能够长期存活下来的原因还是因为语言的设计突出了实用性。事实上,在标准制定过程中,委员会承担了很多压力,这些压力源自于大家对加入更多语言特性的期盼—每一个人都希望将其他编程语言中自己喜欢的特性加入到新的C++中。对于这些热烈而有些许盲目的期盼,委员会成员在Bjarne Stroustrup教授的引导下,选择了不断将许多无关的特性排除在外。其目的是防止C++成为一个千头万绪的但功能互不关联的语言。而如同现在看到的那样,C++11并非大而无序,相反地,许多特性可以良好地协作,进而达到“1 + 1 > 2”的效果。可以说,有了这些努力,今天的读者才能够使用稳定而强大的C++11,而不用担心语言本身存在着混乱状况甚至是冲突。
值得一提的是,虽然在取舍新语言特性方面标准委员会曾面临过巨大压力,但与此同时,标准委员会却没有收集到足够丰富的库的新特性。作为一种通用型语言,C++是否是成功,通常会依赖于不同领域中C++的使用情况,比如科学计算、游戏、制造业、网络编程等。在C++11通过的标准库中,服务于各个领域的新特性确实还是太少了。因此很有可能在下一个版本的C++标准制定中,如何标准化地使用库将成为热门话题,标准委员会也准备好了接受来自这方面的压力。