立足现实 与时俱进:C++ 1991-2006

 论文太长,拆成六部分贴上来

立足现实 与时俱进:C++ 1991-2006

摘要

本文概述C++程序语言的历史,从早期的ISO标准化(1991)到1998年成为ISO标准,到稍后的C++0x标准修正版本(2006)。重点在于阐述理想、约束、编程技术和那些塑造语言的人们,而不是语言特征的细节方面。其中主要的主题有泛型编程和STLC++标准库的算法和容器)。特定的主题包括模板分离编译、异常处理和对嵌入式系统编程的支持。在大部分时期内,C++是一个有着百万级用户的成熟的语言。因此,本文讨论各种C++的使用、技术以及商业的压力,这些都是C++持续演化的背景。

分类和主题描述 K.2[计算历史]:系统

普通术语 设计,编程语言,历史

关键字 C++,语言使用,演化,库,标准化,ISOSTL,多范例编程

1、   导言

199110月,估计的C++用户的数字是400,000[121];而到了200410月,相应的数字是3,270,000[61]。在90年代初C++用户不再呈指数增长但在以后的10年中,C++用户稳定增长。那段时间的工作主要有以下几个方面:

1、使用语言(显然);

2、提供更好的编译器、工具和库;

3、避免语言分裂成各种方言;

4、避免语言和它的社团停滞不前;

显然,C++社团在第一项工作上花费了大量的时间、金钱;ISO C++委员会则倾向于把精力放在第二和第三项工作上;我的主要工作是放在第三和第四项。ISO标准委员会是那些想要改进C++语言和标准库的人们的中心。通过这样的改变,他们(我们)希望能够改进在现实世界中C++编程的艺术地位。C++标准委员会的工作主要放在C++的演化上。

认为C++是用于应用程序开发的平台,许多人想知道为什么—在C++成功之初—C++为什么没有抛弃它从C继承到的东西,走向“食物链的顶层”,成为一个“真正的面向对象”的带“完整”标准库的应用程序编程语言。任何向那个方向转变的趋势都被系统编程、与C的兼容性、同标准委员会有关联的许多社团中使用的C++早期版本兼容所压制。同时,在社团中永远不会有充足的资源用于大工程。另一个重要因素就是由主要软件、硬件提供商带来的朝气蓬勃的商业投机主义,他们看到了C++创建的应用程序是用来区别出他们和他们的竞争对手并且锁定他们用户的机会。其它玩家也看到了这一点,但他们的目标是成长和繁荣。不管怎么样,在委员会所选择的活动领域内并不缺乏支持,提供商的系统、高要求的应用程序依赖于C++。因此,他们提供稳定和最有价值的支持用于标准化工作,通过主持会议的形式,并且—更重要的是关键的技术人员的参与。

不管好坏,ISO C++[66]仍是一个通用的编程语言并且偏向系统编程,有以下特点:

1、更好的C

2、支持数据抽象;

3、支持面向对象编程;

4、支持泛型编程;

从历史的观点对前三项的解释可以[120120]中找到;对支持泛型编程的解释是本文的重点主题。把泛型编程引进主流很可能是C++在这个时期对软件开发社区的最大贡献。

本文的以散乱的年表为次序进行组织:

§1 导言

§2 背景:1979 -1991C++—早期的历史,设计标准,语言特征

§3 1991年的C++世界— C++标准化进程,年表

§4 标准库设施 1991-1998 — C++标准库,重点强调它的最重要和最具创新的组件:STL(容器、算法和迭代器)

§5语言特征 1991-1998 —集中在分离模板编译、异常安全、运行时类型信息和名字空间

§6 标准维护 1997-2003 —为了稳定性,C++标准没有增加新的内容;然而,委员会并没有因此而闲着

§ 7 C ++在真实世界中的使用应用程序领域;应用编程vs系统编程;编程风格;库、应用程序二进制接口(ABI)和环境;工具和研究;JavaC#C;方言

§ 8 C ++0x—目标、约束、语言特征及库设施

§9 回顾影响和冲击;展望C++

重点在于早期和后期:早期塑造了现在的C++C++98);后期则反映了对C++98的经历的反应也适用于C++0x。离开代码讨论怎么在代码中表达想法不可能的,因此,代码的例子用于说明关键的想法、技术和语言设施。这些例子的解释也能被那些不是C++程序员的人们所理解。然而,介绍的焦点是塑造C++的人们、想法、理想、技术和约束,而不是语言-技术细节。对于描述今天的ISO C++是什么样的,请参考[66126]。本文的重点在于回答这些直观的问题:发生了什么事?什么时候发生的?当时谁在场?他们的理由是什么?哪些已经完成(或未完成)?

C++是一个活的语言。本文的主要目标是描述它的演化。然而,它也是一个强调向后兼容的语言。在本文中我描述的代码在今天仍能编译和运行。因此,我倾向于使用现在时态去描述它。考虑到对兼容性的强调,这些代码可能在15年后仍然可以运行。因而,我使用现在时态强调C++演化的一个重要方面。

2、   背景: C++ 1979-1991

C++的早期历史是从我的HOPL-II论文到1991年,在我的《C++程序设计和演化》中指的前15年。它讲述在1994年之前的C++前历史。然而,为设置C++下一个年代的场景,这里简单总结一下C++的早期历史。

C++的设计是为了提供类似于Simula的设施(用于程序组织)和C的高效和灵活性(系统编程)。当时是希望是在有了这些想法的半年之内就将它实现并交付实际的工程使用,它成功了!

在那时,我意识到谨慎或荒谬都不是目标,目标是适度,卷入革新和不合理,在时间标度和严峻的效率和灵活性需求。如果早期没有引入适当的革新,那么效率和灵活性必须维护并付出代价; C++的目标进一步被精炼、详细描述并且更加明确,今天所使用的C++直接反映了它的原来目标。

1979年开始,当我还在Bell实验室的计算机科学研究中心时,我首先设计了一种C方言,称之为“带类的C”。从1979年到1983年,这项工作和与带类的C的经历决定了C++的轮廓。另一个方面,带类的C是基于我在剑桥大学攻读博士生的学习中(分布式系统)使用BCPLSimula的经验。为了攻克系统编程任务,我觉得需要一种工具,它具有如下属性:

·好的工具有Simula用于程序组织的组织类、某种形式的类层次、某种形式的并发支持,和基于类的类型系统的编译期检查。我把这看成是对创造编程进程的一种支持,换句话说,是对设计的支持而不是对编译器的支持。

·好的工具产生的程序跟BCPL一样快并且具有BCPL的将多个分离的已编译单元组合成一个程序能力。简单的链接规定是必不可少的,用于那些用多种语言写的单元,比如CAlgol68FortranBCPL、汇编等,组合成一个程序,从而不会遭遇单一语言中的内在限制的阻碍。

·好的工具应该允许高可移植性的编译器。我的经验就是“好”的编译器通常不会出现直到“下一年”并且是在一种我负担不起的机器上才能使用。这就意味着工具必须有多种编译器来源(没有专利会是对于使用“不常见”机器的用户和没有钱的研究生的一个足够的响应),并且不需要移植复杂的运行时支持系统,在工具和宿主操作系统之间只有非常有限的结合。

我在贝尔实验室的早些年间,这些理想变成了一组用于C++设计的“经验法则”。

·一般规则:

·C++的演化必须由真实问题所驱动

·不涉及毫无结果地对完美的追求

·C++在现在就必须是有用的

·每个特征必须有一个合理的明显的实现

·总是提供转变路径

·C++是一门语言,而不是一个完整的系统

·对每一种已被支持的风格提供综合的支持

·不强迫人们使用特定的编程风格

·设计支持的规则:

·支持健全的设计观点

·提供用于程序组织的设施

·用语言直接表达你的意思

·所有的特征是负担得起的

·允许有用的特征比防止每一种误用更重要

·支持将独立开发组件组合成软件

·语言-技术规则:

       ·没有隐式地违反静态类型系统

·对用户自定义类型提供同内建类型一样好的支持

·局部化

·避免顺序依赖

·如果有疑问,选择更容易教学的特征

·句法问题(通常是以错误的方法)

·消灭预处理器的使用

·底层的编程规则:

·使用传统的(没有提示信息)链接器

·除非有其它理由,否则要与C兼容

·C++之下没有其它低级语言的使用空间(除了汇编程序)

·你不需要为你不需要的东西付出代价(0开销原则)

·如果有疑问,提供手动控制的方法

D&E[121]第四章中有对这些标准的更详细的探讨。C++1989年的release2.0发布时就严格地满足这些标准;基本的压力来自用于C++的模板设计和异常处理的机制,需要背离这些标准中的某些方面。我认为这些准则中最重要的属性是它们只与特定的编程语言特征只有松散的联系,而不是说它们强加约束于处理设计问题的解决方法之上。

2006年,当我再次回顾这个列表时,我惊讶地发现两个设计规则(理想)没有明确的列在上面:

·有直接将C++语言构建到硬件的映射

·标准库是具体的且由C++实现

由于是从C走过来的并且长期工作于C++98标准(§3.1)的制定,这些标准(在那时候和更早期)看起来是这么的显然以致我通常没有去强调它们。其它语言,如LispSmalltalkPythonRubyJavaC#,并不享有这些理想。大多数语言提供抽象的机机制的同时还需要提供大多数有用的数据结构,如stringslisttree、关联数组、vector、矩阵和set,如同内建设施,依赖于其它语言用于(如汇编、CC++)它们的编译器。对于多数的语言,只有C++提供由语言本身所实现一般、灵活、可扩展和高效的容器。从更广的程度说,这些理想来源于CC有这两种属性,但没有定义重要的新类型所需要的抽象机制。

C++的理想从带类的C开始就是应该允许最佳地实现任意的数据结构和在它们之上的操作。这就限制了抽象机制的许多有用的方法[121]的设计,并且导致新的、有趣的编译器实现技术(例如,§4.1)。反过来,如果没有“直接将C++与硬件映射”这个准则,这个理想将很难达成。主要的想法(来自C)是操作符直接反映硬件的操作(算术和逻辑),对内存的访问操作也是由硬件直接提供的(指针和数组)。这两个理想的组合同时使得C++可以有效地用于嵌入式系统编程[131]§6.1)。

2.1带类C的诞生

最终导致C++诞生的工作开始于我们企图去分析UNIX内核,并设法确定怎样才能把它分布到由局域网连接起来的一个计算机网络上。这项工作开始于19794月,在新泽西州Murray Hill的贝尔实验室计算机科学研究中心。有两个子问题很快就浮现出来:怎么分析由内核分布造成的网络流量;怎么模块化内核。这两个问题都要求提供一种描述方式,以便描述复杂系统的模块结构和模块间的通信模式。这正好就是我曾经决定的如果没有合适的工具就绝不去冲击的那一类问题。因此我决定根据自己在剑桥形成的一套标准去开发一种合适的工具。

197910月,我已经完成了预处理器的雏形版本,叫Cpre,它添加了类似于Simula的类到C中。到了19803月,这个预处理器被改进,并且可以支持一个真实的工程和几个实验。我的记录显示到那时止,预处理器在16个系统中得到使用。第一个关键的C++库,叫“任务系统”,支持协程风格的编程[108115]。它对于带类C的有效性是至关重要的,由于这个预处理器而被接受的语言被称之为“带类的C”。

4月到10月这段时期内,从思考一个工具到思考一门语言的转变出现了,但带类的C仍被认为是对C的一种扩展,用以表达模块化和并发。尽管对并发的支持和模仿Simula风格是带类C的主要目标,语言本身并不包含表达并发的原语;然而,继承(类继承)和定义能被预处理器识别的具有特殊意义的类成员函数的组合,被用以编写支持期望的并发风格的库。请注意这里的风格是复数的。我认为这是至关重要的我现在仍持此观点这个语言应该能够表达多种并发的概念

因此,语言提供了一般的机制用于组织程序而不是仅支持特定的应用领域。这使得带类的C和后来的C++成为一门通用语言而不是成为带支持特定应用的扩展的C的变种。后来,提供对特定应用的支持还是对一般抽象机制的支持的选择复杂出现,每一次,答案总是改进抽象机制。

2.2 特征概览

早期的特征包括

·

·派生类

·构造函数和析构函数

·公有/私有访问权控制

·类型检查和隐式函数参数转换

1981年,基于可预知的需求,又添加了几个特征:

·内联函数

·默认参数

·赋值操作符重载

由于带类的C是用预处理器实现的,只有少数的C中没有的特征需要描述,C的全部能力都是用户所可以使用的。这两个方面在当时都受到称赞。特别地,让C成为其子集显著地减小了所需的支持和文档的重写工作。带类的C仍被看作是C的一种方言。而且,类被称为是“用于C语言的一种抽象数据类型设施”[108]。直到1983年,C++提供虚函数[1983],才提出了支持面向对象编程的说法。

关于“带类的C”和后来的C++的公共问题是“为什么使用C?比如说为什么不使用pascal去构建语言?”我对于这个问题的回答可以在[114]找到:

C显然不是最易懂的也不是最容易使用的语言,但为什么这么多人使用它呢?

·C是灵活的:几乎在所有的应用领域都可以使用C,并且几乎每一种编程技巧都可以用CC语言没有排除特定的编程方式的内在限制。

·C是高效的:语义上C是“低级的”,即是说,C的基本概念是传统计算机的基本概念的反映。因此,编译器和程序员可以比较容易地高效利用硬件资源用于C程序。

·C是触手可及的:随便一台计算机,不管是极小的还是最大的超级计算机,都有相应的质量可以接受的C编译器存在,并且C编译器支持一个可接受的完整的、标准的C语言和库。并且还有许多可以获取到的库和支持工具,因此程序员很少需要从零开始设计一个新的系统。

·C是可移植的:一个C程序不能自动的从一台机器移植到另一台机器(操作系统),也不是说这样的移植必须容易完成。然而,通常来说,移植软件的大部分与机器相关的代码在技术和经济上都是可行的。

与这些“第一位”的优点的比较,那些“第二位”的缺点,比如古里古怪的C声明语法和缺乏一些语言构筑的安全就变得不那么重要了。

Pascal被认为是一种玩具语言[78],往C中添加类型检查看起来比往pascal中添加那些认为对系统编程来说是必须的特征要容易和安全得多。在那个时候,我非常害怕犯由于家长式的误导或由于简单的无知从而使得语言在某些重要领域无法应用的错误。10年后的结果清晰表明,选择C作为基础使得我能在系统编程的主流中,而这正是我想要的。语言复杂性的代价也是相当可观的,但(仅仅)是受控的。今天,保持与演化中的C语言和标准库兼容是个严重的问题(参见§7.6)。

除了CSimula,我还把Modula-2AdaSmalltalkMesaClue作为C++的理想的来源[111],因此这并不缺乏灵感。

2.3 工作环境

带类的C的是由我设计和实现,作为在贝尔实验室的计算机科学研究中心的一个研究工程。中心提供了可能的独一无二的环境做这样的工作。1979年当我加入到那里时,我被告知去“做某些有趣的事”,并给适当的计算机资源,鼓励和那些有趣的和有才能的人交流,并在对我的工作进行评估之前给我了一年的时间去实现它。

那里有一种文化倾向,反对需要很多人参与的“伟大的工程”;反对“伟大的计划”,比如让其它人去实现未经考验的论文设计;反对设计者和实现者之间的级别区分。如果你喜欢这样的东西,贝尔实验室和其它组织中有许多这样地方,在那里你可以让你沉迷于这些嗜好。然而,在计算机科学研究中心,对你总有一个要求:如果你不是搞理论的,那么就亲自动手做出某种东西来具体表达你的想法,并找到一些能从你所构建的东西中受益的人。这种环境非常支持这样的工作,并且实验室提供一大群有想法和乐于挑战问题和测试任何构建的东西的人。因此我在[114]中写道:“从来就没有一篇关于C++设计的论文;设计、文档的编写和实现都是同时进行的。自然,C++的前端是用C++写的。也从来没有一个“C++工程”或“C++设计委员会”。解决使用者所遇到的问题和作者与他的朋友、同事间的讨论而产生的问题贯穿整个C++的演化过程。

2.4 从带类的CC++

1982年,我清楚地认识到带类的C只是“中等成功”,并将保持这样直到它消亡。带类的C的成功,我认为是一个满足了它的设计目标的简单的结果:带类的C帮助组织一大组程序,这比C要好得多。至关重要的,这是在没有运行时效率损失、也不需要接受不可接受的开发组织的文化上的改变的基础上达到的。影响它成功的因素部分是提供C所没有的一组有限的设施,部分是用于实现带类的C的预处理器技术。带类的C不提供对那些希望花费巨大努力去获得大致相当的回报的人们的支持:带类的C是向正确方向迈出的重要的一步,但只是一小步。从这个分析得到的结果,我开始设计带类的C的更清晰和可扩展的继任者,并使用传统的编译器技术实现它。

在从带类的CC++的转变中,只有完全理解所有语法和语义才有可能使用恰当的编译器前端对类型检查进行改进。这里提出带类的C的一个主要问题。另外还增加了

·虚函数

·函数名和操作符重载

·引用

·常量const

·许多微小的设施

其中虚函数是主要的增加,因此它使得面向对象编程成为可能。我没有办法让我的同事们相信这些设施的实用性,但把它们看为是支持一种重要编程风格(“范例”)的本质。

经过许多年的使用,release2.0是主要的发行版本,它提供一组重要的扩展特征。比如:

·类型安全链接

·抽象类

·多继承

大部分的扩展和精炼代表了从C++中获得的经验,并且这些特征不可能早一点添加进来,因为我没有太多的远见。

2.5 年表

早些年的年表总结如下:

1979       带类的C的工作开始;第一个带类的C投入使用

1983       第一个C++编译器投入使用

1984       C++命名

1985       Cfront 1.0发布(第一个商用发行版);C++程序设计语言(TC++PL[112]

1986       第一个商用Cfront PC移植(Cfront 1.1,Glockenspiel

1987       第一个GNU C++发布

1988       第一个Oregon软件的C++发布;Zortech的第一个C++发布

1989       Cfront Release 2.0C++注解参考手册[35]ANSI C++委员会(J16)成立                           (华盛顿,D.C.

1990       第一届ANSI X3J16技术会议(Somerset,新泽西州);模板被接纳(西雅图,WA);异常被接纳(Palo Alto,CA);Borland第一个C++发布

1991       第一届ISO WG21会议(Lund,瑞典);Cfront3.0发布(包含模板);C++程序设计语言(第二版)[118]

C++用户的数目平均每7.5个月就翻一倍,从197910月的只有一个用户变成199110

400,000用户[121]。计算用户数目当然很困难,但在早些年,我和那些卖编译器、库、书籍等的

人们有联系,所以我对这些数字相当有信心。这些数字跟IDE提供的数字[61]也是一致的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值