C++Primer中文版(第5版)(顶级畅销书重磅升级全面采用最新 C++ 11标准

【美】Stanley B.Lippman( 斯坦利李普曼)Josee Lajoie(约瑟拉乔伊 )Barbara E. Moo (芭芭拉)

王刚杨巨峰

ISBN 978-7-121-15535-2

20139月出版

定价:128.00

864

16

编辑推荐

C++领域权威潘爱民|孟岩作序,代表技术圈鼎力推荐

一线C++工程师腾讯Milo、微软刘未鹏|陈梓瀚、阿里李云|侯凤林高水准技术审校

如果只读一本C++书籍,相信所有读过的人都会毫不犹豫选择本书,无论初学或老手

既可用来理解C++11规则背后的原理,也可用其新语言特性与标准库来快速构建健壮程序

采用中文版页码全面呈现原书大量交叉引用及详尽索引,新式辅学设置与课后操练用于避开陷阱、巩固良法

内容提要

这本久负盛名的 C++经典教程,时隔八年之久,终迎来史无前例的重大升级。除令全球无数程序员从中受益,甚至为之迷醉的——C++ 大师 Stanley B. Lippman 的丰富实践经验,C++标准委员会原负责人 Josée Lajoie C++标准的深入理解,以及C++ 先驱 Barbara E. Moo C++教学方面的真知灼见外,更是基于全新的 C++11标准进行了全面而彻底的内容更新。非常难能可贵的是,《C++ Primer 中文版(5)》所有示例均全部采用 C++11 标准改写,这在经典升级版中极其罕见——充分体现了 C++ 语言的重大进展及其全面实践。书中丰富的教学辅助内容、醒目的知识点提示,以及精心组织的编程示范,让这本书在 C++ 领域的权威地位更加不可动摇。无论是初学者入门,或是中、高级程序员提升,本书均为不容置疑的首选。

目录

1开始1

2变量和基本类型29

3字符串、向量和数组73

4表达式119

5语句153

6函数181

7227

8IO277

9顺序容器291

10泛型算法335

11关联容器373

12动态内存399

13拷贝控制439

14操作重载与类型转换489

15面向对象程序设计525

16模板与泛型编程577

17标准库特殊设施635

18用于大型程序的工具683

19特殊工具与技术725


       C++11
的新特性

2.1.1long long类型31

2.2.1列表初始化39

2.3.2nullptr常量48

2.4.4constexpr变量59

2.5.1类型别名声明60

2.5.2auto类型指示符61

2.5.3decltype类型指示符62

2.6.1类内初始化65

3.2.2使用autodecltype缩写类型79

3.2.3范围for语句82

3.3定义vector对象的vector(向量的向量)87

3.3.1vector对象的列表初始化88

3.4.1容器的cbegincend函数98

3.5.3标准库beginend函数106

3.6使用autodecltype简化声明115

4.2除法的舍入规则125

4.4用大括号包围的值列表赋值129

4.9sizeof用于类成员139

5.4.3 范围for语句168

6.2.6标准库initializer_list197

6.3.2列表初始化返回值203

6.3.3定义尾置返回类型206

6.3.3使用decltype简化返回类型定义

6.5.2constexpr函数214

7.1.4使用=default生成默认构造函数237

7.3.1类对象成员的类内初始化246

7.5.2委托构造函数261

7.5.6constexpr构造函数268

8.2.1string对象处理文件名284

9.1arrayforward_list容器293

9.2.3 容器的cbegincend函数298

9.2.4容器的列表初始化300

9.2.5容器的非成员函数swap303

9.3.1容器insert成员的返回类型308

9.3.1容器的emplace成员的返回类型308

9.4shrink_to_fit318

9.5.5string的数值转换函数327

10.3.2Lambda表达式346

10.3.3Lambda表达式中的尾置返回类型353

10.3.4标准库bind函数354

11.2.1关联容器的列表初始化377

11.2.3列表初始化pair的返回类型380

11.3.2pair的列表初始化384

11.4无序容器394

12.1智能指针400

12.1.1shared_ptr

12.1.2动态分配对象的列表初始化407

12.1.2auto和动态分配408

12.1.5unique_ptr417

12.1.6weak_ptr420

12.2.1范围for语句不能应用于动态分配数组424

12.2.1动态分配数组的列表初始化424

12.2.1auto不能用于分配数组424

12.2.2allocator::construct可使用任意构造函数428

13.1.5=default用于拷贝控制成员449

13.1.6使用=default阻止拷贝类对象449

13.5用移动类对象代替拷贝类对象469

13.6.1右值引用471

13.6.1标准库move函数472

13.6.2移动构造函数和移动赋值473

13.6.2移动构造函数通常应该是noexcept473

13.6.2移动迭代器480

13.6.3引用限定成员函数483

14.8.3function类模板512

14.9.1explicit类型转换运算符516

15.2.2虚函数的override指示符530

15.2.2通过定义类为final来阻止继承533

15.3虚函数的overridefinal指示符538

15.7.2删除的拷贝控制和继承553

15.7.4继承的构造函数557

16.1.2声明模板类型形参为友元590

16.1.2模板类型别名590

16.1.3模板函数的默认模板参数594

16.1.5实例化的显式控制597

16.2.3模板函数与尾置返回类型605

16.2.5引用折叠规则609

16.2.6static_cast将左值转换为右值612

16.2.7标准库forward函数614

16.4可变参数模板618

16.4sizeof...运算符619

16.4.3可变参数模板与转发622

17.1标准库Tuple类模板636

17.2.2新的bitset运算643

17.3正则表达式库645

17.4随机数库659

17.5.1浮点数格式控制670

18.1.4noexcept异常指示符690

18.1.4noexcept运算符691

18.2.1内联名字空间699

18.3.1继承的构造函数和多重继承712

19.3有作用域的enum736

19.3说明类型用于保存enum对象738

19.3enum的提前声明738

19.4.3标准库mem_fn类模板746

19.6类类型的联合成员751

精彩节摘

推荐序

C++11标准公布之后,C++社群出现了久违的热情,有人甚至叫出“C++的复兴”。指望C++回到20世纪90年代中期那样的地位显然是昧于大势的奢望,但是C++经历了这么多年的打磨与起伏,其在工业界的地位已经非常稳固,在很多领域里已经是不可取代也没必要被取代的统治者。新标准的出现能够大大提升C++开发的效率和质量,因此赢得欢呼也是情理之中。在这种氛围之下,编译器实现的速度也令人惊喜。短短两年时间,从开源的GCCLLVM到专有的Visual C++Intel C++,对于新标准的追踪之快,覆盖之全,与当年C++ 98标准颁布之后迟迟不能落地的窘境相比,可谓对比强烈。当年是热情的开发者反复敦促厂商实现完整标准而不得,为此沮丧无奈,那种心情,至今记忆犹新。时过境迁,今天是编译器实现远远冲在前面,开发者倒是大大地落在了后面。

时至今日,能够基本了解C++11标准的程序员恐怕不多,而能够以新的C++风格开发实践的人更是凤毛麟角。因此,今天的C++开发者面临的一个重要任务就是快速掌握新的C++风格和工具。

而说到教授“正宗的”C++11编程风格,《C++ Primer(第5版)》如同它之前的版本一样,扮演着法定教科书的角色。

一种优秀的编程语言,一定要对于计算这件事情实现一个完整和自洽的抽象。十几年来编程语言领域的竞争,除却实现质量之外,基本上是在比拼抽象的设计。而C语言之所以四十年长盛不衰,根本在于它对于现代计算机提供了一个最底层的高级抽象:凡是比它低的抽象都过于简陋,凡是比它高的抽象都可以用C语言构造出来。C++成功的根本原因,恰恰是因为它虽然试图提供一些高级的抽象机制,但是其根基与C在同一层面。正因为如此,每当你需要走下去直接与硬件对话时,C++成为C之外唯一有效率的选择。我的一个朋友在进行了多年的大型系统软件开发之后,不无感慨地说,C++最大的力量不在于其抽象,恰恰在于其不抽象。

话虽然如此,但是C++之所以脱离C而存在,毕竟还是因为其强大的抽象能力。Bjarne Stroustrup曾经总结说,C++同时支持4种不同的编程风格:C风格、基于对象、面向对象和泛型。事实上,把微软的COM也算进来的话,还可以加上一种“基于组件”的风格。这么多的风格共存于一种语言,就是其强大抽象机制的证明。但是,在C++11以前,C++的抽象可以说存在若干缺陷,其中最严重的是缺少自动内存管理和对象级别的消息发送机制。今天看来,C++ 98只能说是特定历史条件造成的半成品,无论是从语言机制,还是标准库完备程度来说,可以说都存在明显的、不容忽略的缺陷。其直接后果,就是优雅性的缺失和效率的降低。我本人在十年前曾经与当时中国C++社群中不少杰出的人物交流探讨,试图从C++ 98中剪裁出一个小巧、优雅的、自成一体的子集,希望至少在日常编程中,能够在这个子集之内可以写出与当时的JavaC#同样干净明晰的代码。为此我们尝试了各种古怪的模板技巧,并且到处寻找有启发的代码和经验来构造这个语言子集,结果并不理想,甚至可以说是令人非常失望。后来我在我的博客中发表过好几篇文章,探讨所谓的C++风格问题,其实就是说,C++不支持简洁明快的面向对象风格,大家还不如回到基于对象甚至C语言的风格,最多加点模板,省一点代码量。非要面向对象的话,就必须依赖像Qt或者MFC那样的基础设施才可以。

C++11出来之后,增强的语言机制和大为完善的标准库,为C++语言的编程风格带来了革命性的变化。如果能够纯熟地运用C++11的新特征、新机制,那么就能够形成一种简洁优雅的C++编程风格,以比从前更高的效率、更好的质量进行软件开发。对于这种新的风格,我认为“直觉、自然”是最佳的描述。也就是说,解决任何问题不必拘泥于什么笼盖一切的编程思想,也不再沉溺于各种古怪的模板技巧中无法自拔,而是能够根据那个问题本身采用最自然、最符合直觉的方式。C++有自己的一套思维方式,比如容器、算法、作为概念抽象的对象等,很大程度上这套思维方式确实是合乎直觉的。只有到了C++11这一代,C++语言的高级抽象才基本完备,这样一种风格才可能真正落实。因此可以说C++11对于C++ 98而言,不是一次简单的升级,而是一次本质的跃升。

学习新的C++风格,并不是轻而易举的事情。即便对于以前已经精通C++的人来说,熟练掌握rvalue referencemove语义,了解unique_ptrshared_ptrweak_ptr的完整用法,明智地使用function/bindlambda机制,学习C++ Concurrency的新技术,都绝非一朝一夕之功。对于那些初学者来说,这件事情更不简单。

本书无论对于初学者还是提高者,都是最经典的教科全书。一直以来,它的特点就是完整而详细,基本上关于语言本身的问题,都可以在这本书里得到解决。而本书的另一个重要优点,就是其完全基于新的编程风格编写,所有的例子和讲解都遵循C++11标准所体现出来的思路和风格进行,如果能够踏下心来认真学习和练习,那么就能“一次到位”地掌握C++11,尽管可能会比较慢。有经验的C++开发者阅读这本书当然不用从头到尾,选择自己关心的内容学习C++11的新特性就可以,是快速升级自身能力的捷径。

差不多十年前,我提出一个观点,每一个具体的技术领域,只需要读四五本书就够了。以前的C++是个例外,因为语言设计有缺陷,所以要读很多书才知道如何绕过缺陷。现在的C++11完全可以了,大家读四五本书就可以达到合格的水平,这恰恰是语言进步的体现。

本书是这四五本中的一本,而且是“教程+参考书”,扛梁之作,初学者的不二法门。另一本是《C++标准程序库(第2版)》,对于C++熟手来说更为快捷。Scott MeyersEffective C++永远是学习C++者必读的,只不过这本书的第4版不知道什么时候出来。Anthony WilliamsC++ Concurrencyin Action是学习用标准C++开发并发程序的最佳选择。国内的作品,我则高度推荐陈硕的《Linux多线程服务端编程》。这本书的名字赶跑了不少潜在的读者,所以我要特别说明一下。这本书是C++开发的高水平作品,与其说是教你怎么用C++写服务端开发,不如说是教你如何以服务端开发为例子提升C++开发水平。前面几本书都是谈标准C++自己的事情,碰到像iostream这样失败的标准组件也不得不硬着头皮介绍。而这本书是接地气的实践结晶,告诉你面对具体问题时应怎样权衡,C++里什么好用,什么不好用,为什么,等等。

今天的C++学习者是非常幸运的,可以在C++11这个基础上大步向前,不必再因为那些语言的缺陷和过度的技巧而烦恼。大家静下心来认真读几本书,可以打下很好的基础。

孟岩

20138北京

作者简介

Stanley B. Lippman目前是微软公司 VisualC++ 团队的架构师。他从1984年开始在贝尔实验室与C++的设计者Bjarne Stroustrup一起从事C++的设计与开发。他在迪士尼和梦工厂从事动画制作,还担任过JPL的高级顾问。

Josée Lajoie曾经是IBM加拿大研究中心C/C++编译器开发团队的成员,在ISO C++标准委员会工作了7年,担任过ISO核心语言工作组的主席和C++ Report杂志的专栏作家。

Barbara E. Moo是拥有25年软件经验的独立咨询顾问。在AT&T,她与StroustrupLippman一起管理过复杂的C++开发项目。

媒体评论

这本CP5完全可以当做参考书或者字典来用,在语法上遇到什么问题或者编译有问题都可以再这本书里找答案,CP4是非常权威的,毕竟Lippman大大是第一个C++编译器的实现者之一。

这本书的写作方式实在适合国人。他没有中国作家普遍的“讲概念”式的写作手法,而是从因到果,由浅入深,由表及里娓娓道来,从语言的简单用法,到为什么这样设计语言,你不仅能从一个语言使用者的角度看问题,更能站在一个语言设计者的角度思考这种语言的设计优劣。

这是本非常经典的C++书籍,系统全面地介绍了C++语言。本书近一千页,可以看成是学习C++的百科全书。市面上没有哪本其他书籍比本书论述得更广泛,几乎所有的C++知识点本书都有论述而且写得还不错。因为这点,这本书值得每一位C++程序员拥有。

针对C++11而新添加到书中的内容恰到好处地定义了这个新版本。作者在新版本中给出了清晰的阐述,如自动类型、decltype、列表初始化器、右值引用、move操作符、lambda表达式、智能指针等。仅针对C++11的延展,正是这本书的价值所在。

C++是一门强大、难学、令人痛苦,但又是如此美妙的编程语言,在工业界和学术界都可以使用,《C++ Primer(第5版)》即针对初学者,也同样适用于有一定编程经验的读者,最新版本配备了C++11最新标准,是C++粉丝们书架上必备的一本经典著作。

前言

难以计数的程序员已经通过旧版的《C++ Primer》学会了C++语言。而在这段时间中,C++本身又已成熟了许多:语言本身的关注点和程序设计社区的关注点都已大大开阔,已经从主要关注机器效率转变为更多地关注编程效率。

2011年,C++标准委员会发布了ISO C++标准的一个重要修订版。此修订版是C++进化过程中的最新一步,延续了前几个版本对编程效率的强调。新标准的主要目标是:

  • 使语言更为统一,更易于教学

  • 使标准库更简单、安全、使用更高效

  • 使编写高效率的抽象和库变得更简单

因此,在这个版本的《C++ Primer》中,我们进行了彻底的修改,使用了最新的C++标准,即C++11。为了了解新标准是如何全面影响C++语言的,你可以看一下xxiii页至xxv页的新特性列表,其中列出了哪些章节涉及了C++的新特性。

新标准增加的一些特性是具有普适性的,例如用于类型推断的auto。这些新特性使本书中的代码更易于阅读和理解。程序(以及程序员!)可以忽略类型的细节,从而更容易集中精力于程序逻辑上来。其他一些新特性,例如智能指针和允许移动的容器,允许我们编写更为复杂的类,而又不必与错综复杂的资源管理做斗争。因此,在本书中开始讲授如何编写自己的类,会比第4版简单得多。旧标准中阻挡在我们前进路上的很多细节,你我都不必再担心了。

对于本书中涉及新标准定义的新特性的那些部分,我们都已用一个特殊的图标标记出来了。我们希望这些提示标记对那些已经熟悉C++语言核心内容的读者是有帮助的,可以帮助他们决定将注意力投向哪里。对于那些可能尚不支持所有新特性的编译器,我们还希望这些图标能有助于解释这类编译器所给出的编译错误信息。这是因为虽然本书中几乎所有例子都已经用最新版本的GNU编译器编译通过,但我们知道一些读者可能尚未将编译器更新到最新版本。虽然新标准增加了大量新功能,但核心C++语言并未变化,这构成了本书的大部分内容。读者可以借助这些图标来判断哪些功能可能还没有被自己的编译器所支持。

为什么选择这本书?

现代C++语言可以看作是三部分组成的:

  • 低级语言,大部分继承自C语言。

  • 现代高级语言特性,允许我们定义自己的类型以及组织大规模程序和系统。

  • 标准库,它利用高级特性来提供有用的数据结构和算法。

大多数C++教材按照语言进化的顺序来组织其内容。首先讲授C++C子集,然后将C++的更为抽象的一些特性作为高级话题在书的最后进行介绍。这种方式存在两个问题:读者会陷入那些继承自低级程序设计的细节,从而由于挫折感而放弃;读者被强加学习一些坏习惯,随后又需要忘记这些内容。

我们采用一种相反的方法:从一开始就介绍一些语言特性,能让程序员忽略那些继承自低级程序设计的细节。例如,在介绍和使用内置的算术和数组类型时,我们还连同介绍和使用标准库中的类型stringvector。使用这些类型的程序更易写、易理解且更少出错。

太多时候,标准库被当作一种“高级”话题来讲授。很多教材不使用标准库,而是使用基于字符数组指针和动态内存管理的低级程序设计技术。让使用这种低级技术的程序正确运行,要比编写相应的使用标准库的C++代码困难得多。

贯穿全书,我们都在强调好的风格:我们想帮助读者直接养成好的习惯,而不是在获得很多很复杂的知识后再去忘掉那些坏习惯。我们特别强调那些棘手的问题,并对常见的错误想法和陷阱提出警告。

我们还注意解释规则背后的基本原理——使读者不仅知其然,还能知其所以然。我们相信,通过体会程序的工作原理,读者会更快地巩固对语言的理解。

虽然你不必为了学习本书而掌握C语言,但我们还是假定你了解足够多的程序设计知识,了解至少一门现代分程序结构语言,知道如何用这门语言编写、编译以及运行程序。特别是,我们假定你已经使用过变量,编写、调用过函数,也使用过编译器。

5版变化的内容

这一版《C++ Primer》的新特点是用边栏图标来帮助引导读者。C++是一种庞大的编程语言,它提供了一些为特定程序设计问题定制的功能。其中一些功能对大型项目团队有很重要的意义,但对于小型项目开发可能并无必要。因此,并非每个程序员都需要了解每个语言特性的所有细节。我们加入这些边栏图标来帮助读者弄清哪些内容可以随后再学习,而哪些主题是更为重要的。

对于包含C++语言基础内容的章节,我们用一个小人正在读书的图标加以标记。用这个图标标记的那些章节,涵盖了构成语言核心部分的主题。每个人都应该阅读并理解这些章节的内容。

对于那些涉及高级主题或特殊目的主题的章节,我们也进行了标记。在首次阅读时,这些章节可以跳过或快速浏览。我们用一叠书的图标标记这些章节,指出在这些地方,你可以放心地放下书本。快速浏览这些章节可能是一个好主意,这样你就可以知道有这些特性存在。但在真正需要在自己的程序中使用这些特性之前,没有必要花费时间仔细学习这些主题。

为了进一步引导读者的注意力,我们还用放大镜图标标记了特别复杂的概念。我们希望读者对有这种标记的章节能多花费一些时间彻底理解其中的内容。在这些章节中,至少有一些,其主题的重要性可能不是那么明显;但我们认为,你会发现这些章节涉及的主题对理解C++语言原来至关重要。

交叉引用的广泛使用,是本书采用的另外一种阅读帮助。我们希望这些引用能帮助读者容易地翻阅书中的内容,同时还能在后面的例子涉及到前面的内容时容易地跳回到前面。

没有改变的是,《C++ Primer》仍是一本清晰、正确、全面的C++入门教材。我们通过给出一系列复杂度逐步增加的例子来讲授这门语言,这些例子说明了语言特性,展示了如何充分用好C++语言。

本书的结构

我们首先在第I部分和第II部分中介绍了C++语言和标准库的基础内容。这两部分包含的内容足够你编写出有意义的程序,而不是只能写一些玩具程序。大部分程序员基本上都需要掌握本书这两部分所包含的所有内容。

除了讲授C++的基础内容,第I部分和第II部分还有另外一个重要目的:通过使用标准库中定义的抽象设施,使你更加适应高级程序设计技术。标准库设施本身是一组抽象数据类型,通常用C++编写。用来设计标准库的,就是任何C++程序员都可以使用的用来构造类的那些语言特性。我们讲授C++语言的一个经验是,在先学习了使用设计良好的抽象类型后,读者会发现理解如何构造自己的类型更容易了。

只有在经过全面的标准库使用训练,并编写了各种标准库所支持的抽象程序后,我们才真正进入到那些允许你编写自己的抽象类型的C++特性中去。本书的第III部分和第IV部分介绍了如何编写类的形式的抽象类型。第III部分包含基础内容,第IV部分介绍更专门的语言特性。

在第III部分中,我们将介绍拷贝控制问题,以及其他一些使类能像内置类型一样容易使用的技术。类是面向对象编程和泛型编程的基础,第III部分也会介绍这些内容。第IV部分是《C++ Primer》的结束部分,它介绍了一些在组织大型复杂系统时非常有用的语言特性。此外,我们将在附录A中总结标准库算法。

读者帮助

本书的每一章均以一个总结和一个术语表结束,两者一起扼要回顾了这一章的大部分学习重点。读者应该将这些部分作为个人备忘录:如果你不理解某个术语,可以重新学习这一章的相应部分。

在本书中我们还使用了其他一些学习辅助:

  • 重要的术语用黑体显示;我们假定读者已经熟悉的重要术语用楷体显示。每个术语都会列在章末尾的术语表中。

  • 贯穿全书,我们用高亮显示来提醒读者注意语言的重要部分,对常见的陷阱提出警告,建议好的程序设计习惯,以及提供一般性的使用提示。

  • 为了更好地理解语言特性间和概念间的联系,我们提供大量向前的和向后的交叉引用。

  • 对重要的概念和C++新程序员常常觉得最困难的主题,我们提供边栏讨论。

  • 学习任何程序设计语言都需要编写程序。为此,贯穿全书我们提供大量程序示例。扩展示例的源码可从下面的网址获得:http://www.informit.com/title/0321714113

  • 正文中切口处以“形式标注的页码为英文原书页码,便于读者与英文原版书进行对照阅读。

关于编译器的注意事项

在撰写本书时(20127月),编译器提供商正在努力工作,升级编译器以匹配最新的ISO标准。我们使用最多的编译器是GNU编译器4.7.0。本书中只有一小部分特性在此编译器中尚未实现:继承构造函数、成员函数的引用限定符以及正则表达式库。

致谢

我们要特别感谢标准委员会几位现任和前任委员:Dave AbrahamsAndy KoenigStephan T. LavavejJason MerrillJohn SpicerHerb Sutter在准备本书的过程中提供的帮助。在理解新标准的一些更微妙之处,他们为我们提供了宝贵的帮助。我们还要感谢很多致力于升级GNU编译器以实现新标准的人们。

与旧版《C++ Primer》中一样,我们要感谢BjarneStroustrup不知疲倦地为C++工作以及他和作者长时间的友谊。我们还要感谢Alex Stepanov的非凡洞察力,催生了标准库核心的容器和算法。最后,我们要感谢C++标准委员会的所有委员,感谢他们这么多年来在净化、精炼和改进C++语言方面的辛苦工作。

我们衷心感谢审稿人:Marshall ClowJon KalbNevin LiberDr. C. L. TondoDaveed VandevoordeSteve Vinoski,他们建设性的意见帮助我们对全书做出了大大小小的改进。

本书是用Latex及其发行版本中的很多包来进行排版的,我们应该感谢Latex社区成员创造出如此强大的排版工具。

最后,我们要感谢Addison-Wesley公司的优秀员工,他们指导了本书的整个出版过程:Peter Gordon,我们的编辑,他给了我们动力再次修改C++ PrimerKimBoedigheimer,保证了一切按计划进行;Barbara Wood,她在编辑过程中找到了大量编辑错误;还有Elizabeth Ryan,很高兴再次和她共同工作,她指导我们完成了整个设计和生产流程。