全新修订的《C 23高级编程》(第6版)延续经典之作的深厚底蕴,由资深软件工程师Marc Gregoire执笔撰写,再次为高阶编程指南树立新标杆。本书几乎涵盖代号为C 23的新标准的所有特性,并通过经Windows与Linux平台测试的大量实战代码案例,提供深入、透彻的解析。
C 的功能极其广泛,是游戏和商业软件中最流行的高级程序设计语言之一。然而,无法回避的事实是:C 十分复杂,难以掌握。《C 23高级编程(第6版)》将让C 专业人员能跟上最新的发展潮流,保持技术领先。
高效进阶C :
一本助你快速精通C 知识的权威指南
作为追求卓越的C 开发者的首选资源,本书助你实现以下目标。
● 精通C 23最新特性:精准掌握C 23新标准
● 最大化C 潜能:通过高效设计方案释放性能
● 规避开发陷阱:揭示冷门知识点与常见反模式
● 测试与调试之道:学习行业最佳实践
● 性能调优秘籍:掌握提升效率的关键技巧
技术领袖力荐
李建忠、吴咏炜、高博、钱能、朱燕民、吴天明、杨文波、郭龙江、王雷联袂推荐!C 头部自媒体程序喵大人领衔翻译 。
唯一全面覆盖C 23新特性:
深入解析模块(import std)、std::println格式化输出、范围库、协程等新标准,代码示例均基于C 23重构。
现代C 实践指南:
摒弃传统C 风格代码,倡导智能指针、范围循环、结构化绑定等现代范式,提供零历史包袱的学习路径。
案例驱动教学:
通过跨平台(Windows/Linux)测试的实战代码,详解高性能程序设计、内存管理陷阱及并发编程技巧。
工程方法论全覆盖:
独有章节探讨软件生命周期管理(敏捷/瀑布模型)、单元测试、调试技术(内存泄漏检测)、设计模式(工厂/观察者模式)。
??
性能优化秘籍:
专章剖析性能瓶颈定位(gprof/Visual Studio剖析器)、高效缓存策略、对象池技术等工业级调优方案。
配套AI编程资源:
附赠《Vibe Coding 浪潮下的 C 》文档、源代码、附录(面试指南/UML图解), 扫描封底二维码获取。
推 荐 序 一
给《C 20高级编程(第5版)》写了推荐序后,时隔3年,我很高兴看到更新版的《C 23高级编程》问世了。
本书延续之前版本备受赞誉的优点,是一本真正从程序员视角出发、专为程序员量身打造的实用教材,能帮助初、中级C 程序员全面提升其C 专业技能。作者以深厚的专业功底和丰富的一线编程经验,精心打造了这本佳作,提供了完整的到C 23为止的C 语言介绍,从入门语法、高级技巧到软件工程,做了全方位、无死角的介绍,每个知识点都讲解得细致入微。无论你想系统学习C ,还是要找其中某些语法点的参考资料,都将收获实实在在的帮助。
与某些C 教材不同,本书不是简单地在以前的版本上打个小补丁出来卖钱,而是根据当前C 标准(C 23)进行了全面更新。从最基本的Hello World程序,读者就能看到与传统的C 程序的不同:代码使用了import std和std::println这两个新特性,而非使用#include和std::cout。而后面讨论较新特性的时候,也莫不如此,比如,几乎处处可以看到模块和println。类似地,另外一些较新的C 特性(如C 17的string_view和结构化绑定,C 20的三向比较运算符,等等),也较早得到介绍,并在书中多次出现。如果你新学C 的话,可不带历史包袱地看到一门现代的高性能编程语言。如果你之前学过一点C ,也可细细品味现代C 带来的不同,特别是模块引入后对代码组织产生的巨大影响。
既然是个新版本,中文书名里又有C 23,本书当然要重点描述C 23的特性。除了标准库模块和print/println,C 23的主要新特性如显式对象参数、mdspan和Unicode表示改进书里也都进行了介绍。在描述C 23特性时,书的侧边通常会出现特殊的带圈C 23标记,非常清晰。
本书的英文主书名与上一版相同,都是Professional C ,自然,它希望你能专业地对待C 编程。本书的内容编排也十分合理。
第I部分包括三章,以较短篇幅介绍了C 的主要语法和功能,让你快速上手C 。
第II部分的三章不讲语言了,转而讲软件设计。毕竟,我们使用C 的目的是设计出好的软件。写程序不是工作目的。
第III部分是本书的重点,介绍C 编码方法。该部分占了全书的大部分章节和篇幅,具体讲解C 中的各个重要特性和库。日常用到的绝大部分功能,都会在这一部分讲到,如内存管理、基本模板、泛型、错误处理、容器、时间工具等。
第IV部分较为简短,有三章,描述了一些高级技巧,仍然是C 的技术内容。
第V部分又超越了C 语言本身,用了整整7章的篇幅讨论C 项目的软件工程问题,从软件生命周期、测试、调试、设计模式等各个角度进行探讨。这一部分的广度大于深度,对于项目经验不多的程序员来说,尤其有用。
要说我对这本书有什么意见的话,最主要就是作者对广度的追求了。对于某些不推荐(如bind)或不常用的特性,作者仍有所着墨;而对另一些内容(如协程),作者只是一带而过。因为某些特性不常用,描述中也容易发生问题,如14.8.3节的function-try-blocks例子中包含错误行为,29.3.2节的launder例子也有更简单的写法。不过,这也是作者自己的定位选择吧。此外,作者给出的建议里,至少有一项我持保留意见:作者建议把非final类的构造函数以外的方法全部设为virtual这个建议,从我对C 的理解看,也许能适用于某些领域,但绝非放之四海皆准。事实上,标准库的类没有一个标成final,只有少数类中用到了virtual。
无论如何,作为一本中级教材,本书的表现堪称出色。作者的绝大部分建议都极具实用性和可靠性。相信随着学习程度的加深,读者自会有能力去辨别和领悟其中的精妙之处。
好书要有好的翻译。本书的译者有两位我打过交道,都是热心于C 知识传播的年轻才俊。初览译稿,便感受到内容相当清晰晓畅,对于这么厚重的一本大块头教材,也是殊为不易了。在此衷心盼望广大C 学习者都能从此书中受益,成长为更优秀的C 程序员。
吴咏炜
Boolan首席技术咨询师
《C 实战:核心技术与最佳实践》作者
Marc Gregoire是一位软件项目经理/软件架构师,深耕C/C 开发,尤精Microsoft VC 及MFC框架,拥有开发724小时运行于Windows和Linux平台的C 程序的经验(如KNX/EIB家庭自动化软件)。除了C/C ,Marc也擅长C#。
Marc是比利时C 用户组创始人,畅销技术图书Professional C (第2~6版)的作者,C Standard Library Quick Reference(第1~2版)的共同作者,多家出版社多部技术书籍的特约编辑,CppCon C 大会常驻演讲嘉宾,CodeGuru论坛成员(用户名:Marc G)。自2007年以来,他凭借在Visual C 领域的技术影响力,连续十多年荣获微软MVP年度奖项。
Marc毕业于比利时鲁汶大学,先后获得计算机科学工程硕士学位和AI专业的高级硕士学位。职业生涯初期,Marc加入比利时软件咨询公司Ordina,担任技术顾问,主导开发Siemens 和Nokia Siemens Networks面向电信运营商的关键2G/3G系统 (基于Solaris平台),项目团队横跨南美、美国、欧洲、中东、非洲及亚洲多地。Marc现任职于精密光学仪器与工业检测技术领军企业尼康计量(Nikon Metrology),负责X射线、CT及三维几何检测领域的软件架构设计与项目管理。
第I部分 专业的C 简介
第1章 C 和标准库速成 3
1.1 C 速成 3
1.1.1 小程序Hello World 4
1.1.2 命名空间 8
1.1.3 字面量 10
1.1.4 变量 11
1.1.5 运算符 15
1.1.6 枚举 17
1.1.7 结构体 19
1.1.8 条件语句 20
1.1.9 条件运算符 22
1.1.10 逻辑比较运算符 23
1.1.11 三向比较运算符 24
1.1.12 函数 25
1.1.13 属性 27
1.1.14 C风格的数组 30
1.1.15 std::array 31
1.1.16 std::vector 32
1.1.17 std::pair 32
1.1.18 std::optional 33
1.1.19 结构化绑定 34
1.1.20 循环 34
1.1.21 初始化列表 36
1.1.22 C 中的字符串 36
1.1.23 作为面向对象语言的C 36
1.1.24 作用域解析 40
1.1.25 统一初始化 41
1.1.26 指针和动态内存 44
1.1.27 const的用法 47
1.1.28 引用 50
1.1.29 const_cast() 58
1.1.30 异常 59
1.1.31 类型别名 60
1.1.32 类型定义 61
1.1.33 类型推断 61
1.1.34 标准库 64
1.2 第一个大型的C 程序 64
1.2.1 雇员记录系统 64
1.2.2 Employee类 64
1.2.3 Database类 68
1.2.4 用户界面 70
1.2.5 评估程序 72
1.3 本章小结 73
1.4 练习 73
第2章 使用字符串和字符串视图 74
2.1 动态字符串 74
2.1.1 C风格字符串 74
2.1.2 字符串字面量 76
2.1.3 C std::string类 78
2.1.4 数值转换 82
2.1.5 std::string_view类 85
2.1.6 非标准字符串 87
2.2 字符串格式化与打印 87
2.2.1 格式字符串 88
2.2.2 参数索引 89
2.2.3 打印到不同的目的地 89
2.2.4 格式字符串的编译期验证 90
2.2.5 格式说明符 91
2.2.6 格式化转义字符和字符串 94
2.2.7 格式化范围 94
2.2.8 支持自定义类型 96
2.3 本章小结 99
2.4 练习 99
第3章 编码风格 101
3.1 良好外观的重要性 101
3.1.1 事先考虑 101
3.1.2 良好风格的元素 102
3.2 为代码编写文档 102
3.2.1 使用注释的原因 102
3.2.2 注释的风格 106
3.3 分解 109
3.3.1 通过重构分解 110
3.3.2 通过设计分解 111
3.3.3 本书中的分解 111
3.4 命名 111
3.4.1 选择恰当的名称 111
3.4.2 命名约定 112
3.5 使用具有风格的语言特性 113
3.5.1 使用常量 114
3.5.2 使用引用代替指针 114
3.5.3 使用自定义异常 115
3.6 格式 115
3.6.1 关于大括号对齐的争论 115
3.6.2 关于空格和圆括号的争论 116
3.6.3 空格、制表符、换行符 117
3.7 风格的挑战 117
3.8 本章小结 117
3.9 练习 118
第II部分 专业的C 软件设计
第4章 设计专业的C 程序 123
4.1 程序设计概述 123
4.2 程序设计的重要性 124
4.3 C 设计 126
4.4 C 设计的两个原则 126
4.4.1 抽象 126
4.4.2 重用 128
4.5 重用现有代码 130
4.5.1 关于术语的说明 130
4.5.2 决定是否重用代码 130
4.5.3 重用代码的指导原则 132
4.6 设计一个国际象棋程序 137
4.6.1 需求 137
4.6.2 设计步骤 138
4.7 本章小结 143
4.8 练习 143
第5章 面向对象设计 145
5.1 过程化的思考方式 145
5.2 面向对象思想 146
5.2.1 类 146
5.2.2 组件 146
5.2.3 属性 147
5.2.4 行为 147
5.2.5 综合考虑 147
5.3 生活在类的世界里 148
5.3.1 过度使用类 148
5.3.2 过于通用的类 149
5.4 类之间的关系 150
5.4.1 有一个关系 150
5.4.2 是一个关系(继承) 150
5.4.3 有一个与是一个的区别 152
5.4.4 not-a关系 155
5.4.5 层次结构 155
5.4.6 多重继承 156
5.4.7 混入类 157
5.5 本章小结 158
5.6 练习 158
第6章 设计可重用代码 160
6.1 重用哲学 160
6.2 如何设计可重用代码 161
6.2.1 使用抽象 161
6.2.2 构建理想的重用代码 162
6.2.3 设计有用的接口 168
6.2.4 设计成功的抽象 173
6.2.5 SOLID原则 174
6.3 本章小结 174
6.4 练习 175
第III部分 C 编码方法
第7章 内存管理 179
7.1 使用动态内存 180
7.1.1 如何描绘内存 180
7.1.2 分配和释放 181
7.1.3 数组 183
7.1.4 使用指针 189
7.2 数组-指针的对偶性 190
7.2.1 数组退化为指针 190
7.2.2 并非所有指针都是数组 192
7.3 底层内存操作 192
7.3.1 指针运算 192
7.3.2 自定义内存管理 193
7.3.3 垃圾回收 194
7.3.4 对象池 194
7.4 常见的内存陷阱 194
7.4.1 数据缓冲区分配不足以及内存访问越界 194
7.4.2 内存泄漏 196
7.4.3 双重释放和无效指针 198
7.5 智能指针 199
7.5.1 unique_ptr 199
7.5.2 shared_ptr 202
7.5.3 weak_ptr 205
7.5.4 向函数传递参数 206
7.5.5 从函数中返回 206
7.5.6 enable_shared_from_this 207
7.5.7 智能指针与C风格函数的交互 207
7.5.8 过时的、移除的auto_ptr 208
7.6 本章小结 208
7.7 练习 208
第8章 熟悉类和对象 210
8.1 电子表格示例介绍 210
8.2 编写类 211
8.2.1 类定义 211
8.2.2 定义方法 213
8.2.3 使用对象 215
8.2.4 this指针 217
8.2.5 显式对象参数 218
8.3 对象的生命周期 218
8.3.1 创建对象 218
8.3.2 销毁对象 233
8.3.3 对象赋值 234
8.3.4 编译器生成的拷贝构造函数和拷贝赋值运算符 237
8.3.5 复制和赋值的区别 237
8.4 本章小结 238
8.5 练习 239
第9章 精通类和对象 240
9.1 友元 240
9.2 对象中的动态内存分配 241
9.2.1 Spreadsheet类 241
9.2.2 使用析构函数释放内存 244
9.2.3 处理复制和赋值 245
9.2.4 使用移动语义处理移动 250
9.2.5 零规则 260
9.3 与成员函数有关的更多内容 261
9.3.1 static成员函数 261
9.3.2 const成员函数 262
9.3.3 成员函数重载 263
9.3.4 内联成员函数 267
9.3.5 默认参数 268
9.4 constexpr与consteval 269
9.4.1 constexpr关键字 269
9.4.2 consteval关键字 270
9.4.3 constexpr 和 consteval 类 271
9.5 不同的数据成员类型 272
9.5.1 静态数据成员 272
9.5.2 const static数据成员 274
9.5.3 引用数据成员 274
9.6 嵌套类 276
9.7 类内的枚举类型 277
9.8 运算符重载 277
9.8.1 示例:为SpreadsheetCell实现加法 278
9.8.2 重载算术运算符 281
9.8.3 重载比较运算符 282
9.9 创建稳定的接口 286
9.10 本章小结 289
9.11 练习 290
第10章 揭秘继承技术 291
10.1 使用继承构建类 291
10.1.1 扩展类 292
10.1.2 重写成员函数 295
10.2 使用继承重用代码 302
10.2.1 WeatherPrediction类 302
10.2.2 在派生类中添加功能 303
10.2.3 在派生类中替换功能 304
10.3 利用父类 305
10.3.1 父类构造函数 305
10.3.2 父类的析构函数 306
10.3.3 构造函数和析构函数中的虚成员函数调用 307
10.3.4 使用父类成员函数 308
10.3.5 向上转型和向下转型 310
10.4 继承与多态性 311
10.4.1 回到电子表格 311
10.4.2 设计多态性的电子表格单元格 311
10.4.3 SpreadsheetCell基类 312
10.4.4 独立的派生类 313
10.4.5 利用多态性 315
10.4.6 考虑将来 316
10.4.7 提供纯虚成员函数的实现 317
10.5 多重继承 318
10.5.1 从多个类继承 318
10.5.2 名称冲突和歧义基类 319
10.6 有趣而晦涩的继承问题 321
10.6.1 修改重写成员函数的返回类型 322
10.6.2 派生类中添加虚基类成员函数的重载 324
10.6.3 继承的构造函数 325
10.6.4 重写成员函数时的特殊情况 328
10.6.5 派生类中的拷贝构造函数和赋值运算符 334
10.6.6 运行时类型工具 335
10.6.7 非public继承 337
10.6.8 虚基类 337
10.7 类型转换 340
10.7.1 static_cast() 340
10.7.2 reinterpret_cast() 341
10.7.3 dynamic_cast() 342
10.7.4 std::bit_cast() 343
10.7.5 类型转换小结 343
10.8 本章小结 344
10.9 练习 344
第11章 模块、头文件和其他主题 345
11.1 模块 345
11.1.1 非模块化代码 346
11.1.2 标准命名模块 346
11.1.3 模块接口文件 347
11.1.4 模块实现文件 348
11.1.5 从实现中分离接口 349
11.1.6 可见性和可访问性 350
11.1.7 子模块 350
11.1.8 模块划分 351
11.1.9 私有模块片段 353
11.1.10 头文件单元 355
11.1.11 可导入的标准库头文件 355
11.2 预处理指令 357
11.3 链接 358
11.3.1 内部链接 359
11.3.2 extern 关键字 360
11.4 头文件 361
11.4.1 单一定义规则(ODR) 361
11.4.2 重复定义 361
11.4.3 循环依赖 362
11.4.4 查询头文件是否存在 363
11.4.5 模块导入声明 363
11.5 核心语言特性的特性测试宏 363
11.6 static关键字 364
11.6.1 静态数据成员和成员函数 364
11.6.2 函数中的静态变量 364
11.6.3 非局部变量的初始化顺序 365
11.6.4 非局部变量的销毁顺序 365
11.7 C 风格的可变长度参数列表 365
11.7.1 访问参数 366
11.7.2 为什么不应该使用C风格的变长参数列表 367
11.8 本章小结 367
11.9 练习 367
第12章 利用模板编写泛型代码 369
12.1 模板概述 370
12.2 类模板 370
12.2.1 编写类模板 370
12.2.2 编译器处理模板的原理 378
12.2.3 将模板代码分布到多个文件中 379
12.2.4 模板参数 380
12.2.5 成员函数模板 383
12.2.6 类模板的特化 389
12.2.7 从类模板派生 391
12.2.8 继承还是特化 392
12.2.9 模板别名 392
12.3 函数模板 393
12.3.1 函数重载与函数模板 394
12.3.2 函数模板的重载 394
12.3.3 类模板的友元函数模板 395
12.3.4 对模板参数推导的更多介绍 397
12.3.5 函数模板的返回类型 397
12.3.6 简化函数模板的语法 399
12.4 变量模板 399
12.5 概念 400
12.5.1 语法 400
12.5.2 约束表达式 401
12.5.3 预定义的标准概念 403
12.5.4 类型约束的auto 404
12.5.5 类型约束和函数模板 404
12.5.6 类型约束和类模板 407
12.5.7 类型约束和类成员函数 407
12.5.8 基于约束的类模板特化和函数模板重载 408
12.5.9 最佳实践 408
12.6 本章小结 409
12.7 练习 409
第13章 C I/O揭秘 410
13.1 使用流 411
13.1.1 流的含义 411
13.1.2 流的来源和目的地 412
13.1.3 流式输出 412
13.1.4 流式输入 417
13.1.5 对象的输入输出 423
13.1.6 自定义的操作算子 424
13.2 字符串流 425
13.3 基于span的流 426
13.4 文件流 427
13.4.1 文本模式与二进制模式 428
13.4.2 通过seek()和tell()在文件中转移 428
13.4.3 将流链接在一起 430
13.4.4 读取整个文件 431
13.5 双向I/O 431
13.6 文件系统支持库 432
13.6.1 路径 432
13.6.2 目录条目 434
13.6.3 辅助函数 434
13.6.4 目录遍历 434
13.7 本章小结 435
13.8 练习 436
第14章 错误处理 437
14.1 错误与异常 437
14.1.1 异常的含义 438
14.1.2 C 中异常的优点 438
14.1.3 建议 439
14.2 异常机制 439
14.2.1 抛出和捕获异常 440
14.2.2 异常类型 442
14.2.3 按const引用捕获异常对象 443
14.2.4 抛出并捕获多个异常 443
14.2.5 未捕获的异常 446
14.2.6 noexcept说明符 447
14.2.7 noexcept(expression)说明符 448
14.2.8 noexcept(expression)运算符 448
14.2.9 抛出列表 448
14.3 异常与多态性 449
14.3.1 标准异常层次结构 449
14.3.2 在类层次结构中捕获异常 450
14.3.3 编写自己的异常类 451
14.3.4 嵌套异常 453
14.4 重新抛出异常 455
14.5 栈的释放与清理 456
14.5.1 使用智能指针 458
14.5.2 捕获、清理并重新抛出 458
14.6 源码位置 459
14.6.1 日志记录的源码位置 459
14.6.2 在自定义异常中自动嵌入源位置 460
14.7 堆栈跟踪 461
14.7.1 堆栈跟踪库 461
14.7.2 在自定义异常中自动嵌入堆栈跟踪 462
14.8 常见的错误处理问题 464
14.8.1 内存分配错误 464
14.8.2 构造函数中的错误 466
14.8.3 构造函数的function-try-blocks 468
14.8.4 析构函数中的错误 470
14.9 异常安全保证 471
14.10 本章小结 471
14.11 练习 471
第15章 C 运算符重载 473
15.1 运算符重载概述 473
15.1.1 重载运算符的原因 474
15.1.2 运算符重载的限制 474
15.1.3 运算符重载的选择 474
15.1.4 不应重载的运算符 476
15.1.5 可重载运算符小结 476
15.1.6 右值引用 479
15.1.7 优先级和结合性 480
15.1.8 关系运算符 481
15.1.9 替代符号 481
15.2 重载算术运算符 482
15.2.1 重载一元负号和一元正号运算符 482
15.2.2 重载递增和递减运算符 482
15.3 重载按位运算符和二元逻辑运算符 483
15.4 重载插入运算符和提取运算符 483
15.5 重载下标运算符 485
15.5.1 通过operator[]提供只读访问 488
15.5.2 多维下标运算符 489
15.5.3 非整数数组索引 490
15.5.4 静态下标运算符 490
15.6 重载函数调用运算符 491
15.7 重载解除引用运算符 492
15.7.1 实现operator* 494
15.7.2 实现operator-> 494
15.7.3 operator.*和operator ->*的含义 494
15.8 编写转换运算符 495
15.8.1 auto运算符 496
15.8.2 使用显式转换运算符解决多义性问题 496
15.8.3 用于布尔表达式的转换 497
15.9 重载内存分配和内存释放运算符 498
15.9.1 new和delete的工作原理 499
15.9.2 重载operator new和operator delete 500
15.9.3 显式地删除/默认化operator new和operator delete 502
15.9.4 重载带有额外参数的operator new和operator delete 502
15.9.5 重载带有内存大小参数的operator delete 503
15.10 重载用户定义的字面量运算符 504
15.10.1 标准库定义的字面量 504
15.10.2 用户自定义的字面量 504
15.11 本章小结 506
15.12 练习 506
第16章 C 标准库概述 508
16.1 编码原则 509
16.1.1 使用模板 509
16.1.2 使用运算符重载 509
16.2 C 标准库概述 509
16.2.1 字符串 509
16.2.2 正则表达式 510
16.2.3 I/O流 510
16.2.4 智能指针 510
16.2.5 异常 510
16.2.6 标准整数类型 511
16.2.7 数学工具 511
16.2.8 整数比较 512
16.2.9 位操作 512
16.2.10 时间和日期工具 513
16.2.11 随机数 513
16.2.12 初始化列表 513
16.2.13 Pair和Tuple 513
16.2.14 词汇类型 513
16.2.15 函数对象 514
16.2.16 文件系统 514
16.2.17 多线程 514
16.2.18 类型萃取 514
16.2.19 标准库特性测试宏 514
16.2.20 515
16.2.21 源位置 516
16.2.22 堆栈跟踪 516
16.2.23 容器 516
16.2.24 算法 522
16.2.25 范围库 529
16.2.26 标准库中还缺什么 530
16.3 本章小结 530
16.4 练习 530
第17章 理解迭代器与范围库 532
17.1 迭代器 532
17.1.1 获取容器的迭代器 534
17.1.2 迭代器萃取 536
17.1.3 示例 536
17.1.4 使用迭代器特性进行函数分发 537
17.2 流迭代器 539
17.2.1 输出流迭代器:ostream_iterator 539
17.2.2 输入流迭代器:istream_iterator 540
17.2.3 输入流迭代器:istreambuf_iterator 540
17.3 迭代器适配器 540
17.3.1 插入迭代器 541
17.3.2 逆向迭代器 542
17.3.3 移动迭代器 543
17.4 范围 544
17.4.1 约束算法 545
17.4.2 视图 547
17.4.3 范围工厂 552
17.4.4 将范围转换为容器 554
17.5 本章小结 555
17.6 练习 556
第18章 标准库容器 557
18.1 容器概述 557
18.1.1 对元素的要求 558
18.1.2 异常和错误检查 559
18.2 顺序容器 559
18.2.1 vector 560
18.2.2 vector特化 578
18.2.3 deque 578
18.2.4 list 579
18.2.5 forward_list 581
18.2.6 array 584
18.3 顺序视图 585
18.3.1 span 585
18.3.2 mdspan 587
18.4 容器适配器 588
18.4.1 queue 588
18.4.2 priority_queue 591
18.4.3 stack 593
18.5 关联容器 593
18.5.1 有序关联容器 594
18.5.2 无序关联容器/哈希表 607
18.5.3 平坦集合和平坦映射关联容器适配器 613
18.5.4 关联容器的性能 614
18.6 其他容器 614
18.6.1 标准C风格数组 614
18.6.2 string 615
18.6.3 流 615
18.6.4 bitset 616
18.7 本章小结 620
18.8 练习 620
第19章 函数指针、函数对象、lambda表达式 622
19.1 函数指针 622
19.1.1 findMatches()?使用函数指针 623
19.1.2 findMatches()?函数模板 624
19.1.3 Windows DLL和函数指针 625
19.2 指向成员函数(和数据成员)的指针 626
19.3 函数对象 627
19.3.1 编写第一个函数对象 627
19.3.2 标准库中的函数对象 627
19.4 多态功能包装器 634
19.4.1 std::function 634
19.4.2 std::move_only_function 635
19.5 lambda表达式 636
19.5.1 语法 636
19.5.2 lambda表达式作为参数 640
19.5.3 泛型lambda表达式 641
19.5.4 lambda捕获表达式 641
19.5.5 模板化lambda表达式 642
19.5.6 lambda 表达式作为返回类型 643
19.5.7 未计算上下文中的lambda表达式 643
19.5.8 默认构造、拷贝和赋值 643
19.5.9 递归lambda表达式 644
19.6 调用 644
19.7 本章小结 645
19.8 练习 645
第20章 掌握标准库算法 647
20.1 算法概述 647
20.1.1 find() 和 find_if() 算法 648
20.1.2 accumulate() 算法 650
20.1.3 在算法中使用移动语义 651
20.1.4 算法回调 651
20.2 算法详解 652
20.2.1 非修改序列算法 652
20.2.2 修改序列算法 657
20.2.3 操作算法 665
20.2.4 分区算法 667
20.2.5 排序算法 668
20.2.6 二分查找算法 669
20.2.7 集合算法 670
20.2.8 最小/最大算法 672
20.2.9 并行算法 673
20.2.10 数值处理算法 674
20.2.11 约束算法 676
20.3 本章小结 678
20.4 练习 678
第21章 字符串的本地化与正则表达式 680
21.1 本地化 680
21.1.1 宽字符 680
21.1.2 非西方字符集 681
21.1.3 本地化字符串字面量 683
21.1.4 locale和facet 683
21.2 正则表达式 688
21.2.1 ECMAScript语法 689
21.2.2 regex库 693
21.2.3 regex_match() 694
21.2.4 regex_search() 696
21.2.5 regex_iterator 697
21.2.6 regex_token_iterator 698
21.2.7 regex_replace() 700
21.3 本章小结 702
21.4 练习 702
第22章 日期和时间工具 704
22.1 编译期有理数 704
22.2 持续时间 706
22.2.1 示例与duration转换 707
22.2.2 预定义的duration 709
22.2.3 标准字面量 710
22.2.4 hh_mm_ss 710
22.3 时钟 710
22.3.1 打印当前时间 711
22.3.2 执行时间 712
22.4 时间点 712
22.5 日期 714
22.5.1 创建日期 714
22.5.2 打印日期 716
22.5.3 日期运算 717
22.6 时区 717
22.7 本章小结 718
22.8 练习 719
第23章 随机数工具 720
23.1 C风格随机数生成器 720
23.2 随机数引擎 721
23.3 随机数引擎适配器 722
23.4 预定义的随机数引擎和引擎适配器 723
23.5 生成随机数 723
23.6 随机数分布 725
23.7 本章小结 728
23.8 练习 728
第24章 其他词汇类型 729
24.1 variant 729
24.2 any 731
24.3 元组 732
24.3.1 分解元组 734
24.3.2 串联 735
24.3.3 比较 736
24.3.4 make_from_tuple() 737
24.3.5 apply() 737
24.4 optional:单子式操作 737
24.5 expected 738
24.6 本章小结 741
24.7 练习 741
第IV部分 掌握C 的高级特性
第25章 自定义和扩展标准库 745
25.1 分配器 745
25.2 扩展标准库 746
25.2.1 扩展标准库的原因 747
25.2.2 编写标准库算法 747
25.2.3 编写标准库容器 749
25.3 本章小结 773
25.4 练习 774
第26章 高级模板 775
26.1 深入了解模板参数 775
26.1.1 深入了解模板类型参数 775
26.1.2 template template参数介绍 778
26.1.3 深入了解非类型模板参数 780
26.2 类模板部分特化 781
26.3 通过重载模拟函数部分特化 784
26.4 模板递归 785
26.4.1 N维网格:初次尝试 786
26.4.2 真正的N维网格 786
26.5 变参模板 788
26.5.1 类型安全的变长参数列表 788
26.5.2 可变数目的混入类 791
26.5.3 折叠表达式 792
26.6 模板元编程 794
26.6.1 编译期阶乘 794
26.6.2 循环展开 795
26.6.3 打印元组 795
26.6.4 类型萃取 798
26.6.5 模板元编程总结 809
26.7 本章小结 809
26.8 练习 809
第27章 C 多线程编程 810
27.1 多线程编程概述 811
27.1.1 争用条件 812
27.1.2 撕裂 813
27.1.3 死锁 813
27.1.4 伪共享 814
27.2 线程 815
27.2.1 通过函数指针创建线程 815
27.2.2 通过函数对象创建线程 816
27.2.3 通过lambda创建线程 817
27.2.4 通过成员函数指针创建线程 818
27.2.5 线程本地存储 818
27.2.6 取消线程 819
27.2.7 自动join线程 819
27.2.8 从线程获得结果 820
27.2.9 复制和重新抛出异常 821
27.3 原子操作库 823
27.3.1 原子操作 825
27.3.2 原子智能指针 826
27.3.3 原子引用 826
27.3.4 使用原子类型 826
27.3.5 等待原子变量 828
27.4 互斥 829
27.4.1 互斥量类 829
27.4.2 锁 831
27.4.3 std::call_once 834
27.4.4 互斥量的用法示例 835
27.5 条件变量 838
27.5.1 虚假唤醒 839
27.5.2 使用条件变量 839
27.6 latch 840
27.7 barrier 841
27.8 semaphore 843
27.9 future 843
27.9.1 std::promise和std::future 844
27.9.2 std::packaged_task 845
27.9.3 std::async 845
27.9.4 异常处理 846
27.9.5 std::shared_future 847
27.10 示例:多线程的Logger类 848
27.11 线程池 852
27.12 协程 852
27.13 线程设计和最佳实践 854
27.14 本章小结 855
27.15 练习 855
第V部分 C 软件工程
第28章 充分利用软件工程方法 859
28.1 过程的必要性 859
28.2 软件生命周期模型 860
28.2.1 瀑布模型 860
28.2.2 生鱼片模型 862
28.2.3 螺旋类模型 862
28.2.4 敏捷 864
28.3 软件工程方法论 865
28.3.1 Scrum 865
28.3.2 UP 867
28.3.3 RUP 868
28.3.4 极限编程 869
28.3.5 软件分流 872
28.4 构建自己的过程和方法 873
28.4.1 对新思想采取开放态度 873
28.4.2 提出新想法 873
28.4.3 知道什么行得通、什么行不通 873
28.4.4 不要逃避 873
28.5 版本控制 873
28.6 本章小结 875
28.7 练习 875
第29章 编写高效的C 程序 876
29.1 性能和效率概述 876
29.1.1 提升效率的两种方式 877
29.1.2 两种程序 877
29.1.3 C 是不是低效的语言 877
29.2 语言层次的效率 877
29.2.1 高效地操纵对象 878
29.2.2 预分配内存 881
29.2.3 使用内联函数 881
29.2.4 标记无法访问的代码 881
29.3 设计层次的效率 882
29.3.1 尽可能多地缓存 882
29.3.2 使用对象池 883
29.4 剖析 888
29.4.1 使用gprof的剖析示例 888
29.4.2 使用Visual C 2022的剖析示例 895
29.5 本章小结 897
29.6 练习 897
第30章 熟练掌握测试技术 898
30.1 质量控制 899
30.1.1 谁负责测试 899
30.1.2 bug的生命周期 899
30.1.3 bug跟踪工具 900
30.2 单元测试 901
30.2.1 单元测试方法 902
30.2.2 单元测试过程 902
30.2.3 实际中的单元测试 905
30.3 模糊测试 912
30.4 高级测试 913
30.4.1 集成测试 913
30.4.2 系统测试 914
30.4.3 回归测试 914
30.5 用于成功测试的建议 915
30.6 本章小结 915
30.7 练习 916
第31章 熟练掌握调试技术 917
31.1 调试的基本定律 917
31.2 bug分类学 918
31.3 避免bug 918
31.4 为bug做好规划 919
31.4.1 错误日志 919
31.4.2 调试跟踪 920
31.4.3 断言 927
31.4.4 崩溃转储 928
31.5 调试技术 928
31.5.1 重现bug 928
31.5.2 调试可重复的bug 929
31.5.3 调试不可重现的bug 929
31.5.4 调试退化 930
31.5.5 调试内存问题 930
31.5.6 调试多线程程序 934
31.5.7 调试示例:文章引用 934
31.5.8 从ArticleCitations示例中总结出的教训 945
31.6 本章小结 946
31.7 练习 946
第32章 使用设计技术和框架 948
32.1 容易忘记的语法 949
32.1.1 编写类 949
32.1.2 派生类 950
32.1.3 编写lambda表达式 951
32.1.4 使用复制和交换惯用语法 951
32.1.5 抛出和捕获异常 952
32.1.6 写入类模板 953
32.1.7 约束模板参数 953
32.1.8 写入文件 954
32.1.9 读取文件 954
32.2 始终存在更好的方法 955
32.2.1 RAII 955
32.2.2 双分派 958
32.2.3 混入类 961
32.3 面向对象的框架 965
32.3.1 使用框架 965
32.3.2 MVC范型 966
32.4 本章小结 967
32.5 练习 967
第33章 应用设计模式 968
33.1 策略模式 969
33.1.1 示例:日志机制 969
33.1.2 基于策略logger的实现 969
33.1.3 使用基于策略的Logger 970
33.2 抽象工厂模式 971
33.2.1 示例:模拟汽车工厂 971
33.2.2 实现抽象工厂 972
33.2.3 使用抽象工厂 973
33.3 工厂方法模式 974
33.3.1 示例:模拟第二个汽车工厂 974
33.3.2 实现工厂的方法 975
33.3.3 使用工厂方法 976
33.3.4 其他用法 978
33.4 其他工厂模式 978
33.5 适配器模式 979
33.5.1 示例:适配Logger类 979
33.5.2 实现适配器 980
33.5.3 使用适配器 981
33.6 代理模式 981
33.6.1 示例:隐藏网络连接问题 981
33.6.2 实现代理 981
33.6.3 使用代理 982
33.7 迭代器模式 983
33.8 观察者模式 983
33.8.1 示例:从主题中暴露事件 983
33.8.2 实现观察者 984
33.8.3 使用观察者 985
33.9 装饰器模式 986
33.9.1 示例:在网页中定义样式 986
33.9.2 装饰器的实现 987
33.9.3 使用装饰器 988
33.10 责任链模式 988
33.10.1 示例:事件处理 989
33.10.2 实现责任链 989
33.10.3 使用责任链 990
33.11 单例模式 991
33.11.1 日志记录机制 992
33.11.2 实现单例 992
33.11.3 使用单例 994
33.12 本章小结 994
33.13 练习 994
第34章 开发跨平台和跨语言的应用程序 996
34.1 跨平台开发 996
34.1.1 架构问题 997
34.1.2 实现问题 999
34.1.3 平台专用功能 1001
34.2 跨语言开发 1002
34.2.1 混用C和C 1002
34.2.2 改变范型 1002
34.2.3 链接C代码 1005
34.2.4 从C#调用C 代码 1006
34.2.5 在C 中使用C#代码及在C#中使用C 代码 1008
34.2.6 在Java中使02用JNI调用C 代码 1009
34.2.7 从C 代码调用脚本 1011
34.2.8 从脚本调用C 代码 1011
34.2.9 从C 调用汇编代码 1013
34.3 本章小结 1014
34.4 练习 1014
以下内容可扫封底二维码下载
第VI部分 附录
附录A C 面试 1019
附录B 参考文献及相关介绍 1039
附录C 标准库头文件 1048
附录D UML简介 1054