內容介紹
榮耀與劉未鵬合譯的重量級編程圖書,市面上唯一一本討論C++不足之處,並給出解決方案的圖書。即便是C++陣營里最忠實的信徒,也不得不承認:C++語言並不完美。實際上,世界上也沒有完美的程式語言。
如何克服C++類型系統的不足?在C++中,如何利用約束、契約和斷言來實施軟體設計?如何處理被C++標準所忽略的動態庫、靜態對象以及執行緒等有關的問題?隱式轉換有何替代方案?本書將為你一一解答這些問題。針對C++的每一個不完美之處,本書都具體地分析原因,並探討實用的解決方案。書中也不乏許多作者創新的、你從未聽說過或使用的技術,但這些確實能幫助你成為C++方面的專家。
本書適合有一定經驗的C++程式設計師和項目經理閱讀,也適合對C++編程的一些專門或高級話題感興趣的讀者參考。
作者介紹
Matthew Wilson是一名軟體開發顧問,也是STLSoft庫的創建者。他為雙月刊C/C++ Users Journal撰寫關於將C/C++與其他語言和技術進行整合的專欄文章,同時也是C++ Experts Forum線上專欄作家。Wilson有十餘年C++開發經驗。榮耀,南京師範大學教師。他是一名C++講師和研究者,譯有《C++必知必會》、《C++ Templates全覽》以及《C++ Template Metaprogramming中文版》(中文繁體版)等,並在期刊雜誌上發表過多篇文章。他原任電力自動化研究院工程師與項目經理,是數個企業級信息系統項目負責人,詳見www.royaloo.com。
劉未鵬,南京大學計算機系碩士畢業,現就職於微軟亞洲研究院創新工程中心,部落格地址為http://mindhacks.cn/。
作品目錄
目 錄第一部分 基礎知識 1
第1章 強制設計:約束、契約和斷言 3
1.1 綠蛋和火腿 4
1.2 編譯期契約:約束 4
1.2.1 must_have_base() 5
1.2.2 must_be_subscriptable() 6
1.2.3 must_be_subscriptable_
as_decayable_pointer() 6
1.2.4 must_be_pod() 7
1.2.5 must_be_same_size() 9
1.2.6 使用約束 10
1.2.7 約束和TMP 11
1.2.8 約束:尾聲 11
1.3 運行期契約:前置條件、後
置條件和不變式 12
1.3.1 前置條件 13
1.3.2 後置條件 13
1.3.3 類不變式 15
1.3.4 檢查?總是進行 16
1.3.5 DbC還是不DbC 17
1.3.6 運行期契約:尾聲 17
1.4 斷言 18
1.4.1 獲取訊息 19
1.4.2 不恰當的斷言 20
1.4.3 語法以及64位指針 21
1.4.4 避免使用verify() 21
1.4.5 為你的斷言命名 22
1.4.6 避免使用#ifdef_DEBUG 23
1.4.7 DebugBreak()和int 3 24
1.4.8 靜態/編譯期斷言 24
1.4.9 斷言:尾聲 26
第2章 對象生命期 27
2.1 對象生命周期 27
2.2 控制你的客戶端 28
2.2.1 成員類型 28
2.2.2 預設構造函式 28
2.2.3 拷貝構造函式 29
2.2.4 拷貝賦值 29
2.2.5 new和delete 30
2.2.6 虛析構 30
2.2.7 explicit 31
2.2.8 析構函式 31
2.2.9 友元 32
2.3 MIL及其優點 33
2.3.1 取得一塊更大的場地 35
2.3.2 成員順序依賴 37
2.3.3 offsetof() 38
2.3.4 MIL:尾聲 39
第3章 資源封裝 40
3.1 資源封裝分類 40
3.2 POD類型 41
3.2.1 直接操縱 41
3.2.2 API函式和透明類型 42
3.2.3 API函式和不透明類型 42
3.3 外覆代理類 43
3.4 RRID類型 45
3.4.1 預設初始化:緩式初
始化 46
3.4.2 未初始化 48
3.5 RAII類型 51
3.5.1 常性RAII和易變性
RAII 51
3.5.2 內部初始化和外部初
始化 53
3.5.3 RAII排列 53
3.6 RAII:尾聲 54
3.6.1 不變式 54
3.6.2 錯誤處理 54
第4章 數據封裝和值類型 55
4.1 數據封裝的分類學 55
4.2 值類型和實體類型 56
4.3 值類型的分類學 56
4.4 開放式類型 58
4.4.1 POD開放式類型 58
4.4.2 C++數據結構 59
4.5 封裝式類型 60
4.6 值類型 61
4.7 算術值類型 62
4.8 值類型:尾聲 63
4.9 封裝:尾聲 64
第5章 對象訪問模型 68
5.1 確定性生命期 68
5.2 返回拷貝 70
5.3 直接交給調用者 70
5.4 共享對象 71
第6章 域守衛類 73
6.1 值 73
6.2 狀態 78
6.3 API和服務 83
6.3.1 API 83
6.3.2 服務 86
6.4 語言特性 87
第二部分 生存在現實世界 89
第7章 ABI 91
7.1 共享代碼 91
7.2 C ABI需求 93
7.2.1 結構布局 93
7.2.2 調用約定、符號名以及
目標檔案格式 94
7.2.3 靜態連線 94
7.2.4 動態連線 95
7.3 C++ ABI需求 96
7.3.1 對象布局 97
7.3.2 虛函式 97
7.3.3 調用約定和名字重整 97
7.3.4 靜態連線 99
7.3.5 動態連線 99
7.4 現在知道怎么做了 100
7.4.1 extern“C” 100
7.4.2 名字空間 103
7.4.3 extern“C++” 103
7.4.4 獲得C++類的句柄 106
7.4.5 “由實現定義”的隱患 108
第8章 跨邊界的對象 110
8.1 近乎可移植的虛函式表 110
8.1.1 虛函式表布局 111
8.1.2 動態操縱虛函式表 113
8.2 可移植的虛函式表 114
8.2.1 利用宏進行簡化 116
8.2.2 兼容的編譯器 116
8.2.3 可移植的服務端對象 117
8.2.4 簡化可移植接口的
實現 119
8.2.5 C客戶代碼 120
8.2.6 OAB的約束 120
8.3 ABI/OAB尾聲 121
第9章 動態庫 123
9.1 顯式調用函式 123
9.1.1 顯式調用C++函式 124
9.1.2 打破C++訪問控制 125
9.2 同一性:連線單元和連線
空間 125
9.2.1 連線單元 125
9.2.2 連線空間 126
9.2.3 多重身份 126
9.3 生命期 127
9.4 版本協調 128
9.4.1 丟失的函式 128
9.4.2 變化的簽名 128
9.4.3 行為的改變 129
9.4.4 常量 129
9.5 資源所有權 130
9.5.1 共享池 130
9.5.2 返還給被調用方 130
9.6 動態庫:尾聲 131
第10章 執行緒 132
10.1 對整型值的同步訪問 133
10.1.1 作業系統函式 134
10.1.2 原子類型 135
10.2 對(代碼)塊的同步訪問:
臨界區 136
10.2.1 進程間互斥體和進程內互斥體 137
10.2.2 自旋互斥體 138
10.3 原子整型的性能 139
10.3.1 基於互斥體的原子
整型 139
10.3.2 運行期按架構派發 141
10.3.3 性能比較 142
10.3.4 原子整型操作:尾聲 143
10.4 多執行緒擴展 144
10.4.1 synchronized 144
10.4.2 匿名synchronized 147
10.4.3 atomic 147
10.5 執行緒相關的存儲 148
10.5.1 重入 148
10.5.2 執行緒相關的數據/線
程局部存儲 148
10.5.3 declspec(thread)和
TLS 150
10.5.4 Tss庫 150
10.5.5 TSS的性能 155
第11章 靜態對象 156
11.1 非局部靜態對象:全局對象 157
11.1.1 編譯單元內的順序性 158
11.1.2 編譯單元間的順序性 159
11.1.3 利用main()避免全局
變數 161
11.1.4 全局對象尾聲:順
序性 162
11.2 單件 163
11.2.1 Meyers單件 163
11.2.2 Alexandrescu單件 164
11.2.3 即時Schwarz計數器:
一個極妙的主意 165
11.2.4 對API計數 166
11.2.5 被計數的API、外覆類、
代理類:最終得到一個
順序化的單件 168
11.3 函式範圍內的靜態對象 169
11.3.1 犧牲緩式求值能力 171
11.3.2 自旋互斥體是救星 171
11.4 靜態成員 172
11.4.1 解決連線問題 172
11.4.2 自適應代碼 174
11.5 靜態對象:尾聲 175
第12章 最佳化 176
12.1 內聯函式 176
12.1.1 警惕過早最佳化 176
12.1.2 只含有頭檔案的庫 177
12.2 返回值最佳化 177
12.3 空基類最佳化 180
12.4 空派生類最佳化 183
12.5 阻止最佳化 184
第三部分 語言相關的議題 188
第13章 基本類型 189
13.1 可以給我來一個位元組嗎 189
13.1.1 標明符號 190
13.1.2 一切都在名字之中 190
13.1.3 窺探void內部 191
13.1.4 額外的安全性 191
13.2 固定大小的整型 192
13.2.1 平台無關性 193
13.2.2 類型相關的行為 195
13.2.3 固定大小的整型:
尾聲 197
13.3 大整型 198
13.4 危險的類型 200
13.4.1 引用和臨時對象 200
13.4.2 bool 201
第14章 數組和指針 204
14.1 不要重複你自己 204
14.2 數組退化為指針 206
14.2.1 下標索引操作符的
交換性 206
14.2.2 阻止退化 208
14.3 dimensionof() 209
14.4 無法將數組傳遞給函式 211
14.5 數組總是按地址進行傳遞 214
14.6 派生類的數組 215
14.6.1 通過指針保存多態
類型 216
14.6.2 提供非預設的構造
函式 217
14.6.3 隱藏向量式new和
delete 218
14.6.4 使用std::vector 218
14.6.5 確保類型的大小相同 219
14.7 不能擁有多維數組 222
第15章 值 226
15.1 NULL的是非曲直 226
15.2 回到0 232
15.3 屈服於事實 235
15.4 字面量 236
15.4.1 整型 236
15.4.2 後綴 238
15.4.3 字元串 240
15.5 常量 243
15.5.1 簡單常量 243
15.5.2 類類型常量 244
15.5.3 成員常量 245
15.5.4 類類型的成員常量 248
第16章 關鍵字 251
16.1 interface 251
16.2 temporary 253
16.3 owner 256
16.4 explicit(_cast) 261
16.4.1 使用顯式訪問函式 263
16.4.2 模擬顯式轉換 264
16.4.3 使用特性墊片 265
16.5 unique 266
16.6 final 267
16.7 不被支持的關鍵字 267
第17章 語法 270
17.1 類的代碼布局 270
17.2 條件表達式 273
17.2.1 “使它布爾” 273
17.2.2 一個危險的賦值 275
17.3 for 277
17.3.1 初始化作用域 277
17.3.2 異質初始化類型 278
17.4 變數命名 280
17.4.1 匈牙利命名法 280
17.4.2 成員變數 281
第18章 Typedef 284
18.1 指針typedef 286
18.2 定義裡面有什麼 288
18.2.1 概念性的類型定義 288
18.2.2 上下文相關的類型
定義 289
18.3 別名 292
18.3.1 錯誤的概念性類型
互換 293
18.3.2 不能對概念性類型進
行重載 294
18.4 true_typedef 294
18.5 好的、壞的、醜陋的 300
18.5.1 好的typedef 300
18.5.2 壞的typedef 303
18.5.3 可疑的typedef 304
第四部分 感知式轉換 308
第19章 強制 310
19.1 隱式轉換 310
19.2 C++中的強制 311
19.3 適合使用C強制的場合 312
19.4 模仿強制 314
19.5 explicit_cast 316
19.6 literal_cast 321
19.7 union_cast 323
19.8 comstl::interface_cast 327
19.8.1 interface_cast_addref 328
19.8.2 interface_cast_noaddref 329
19.8.3 interface_cast_test 329
19.8.4 接口強制操作符的
實現 330
19.8.5 保護引用計數 333
19.8.6 interface_cast_base 334
19.8.7 IID_traits 335
19.8.8 interface_cast 尾聲 336
19.9 boost::polymorphic_cast 337
19.10 強制:尾聲 339
第20章 墊片 341
20.1 擁抱變化 擁抱自由 341
20.2 特性墊片 344
20.3 邏輯墊片 346
20.4 控制墊片 347
20.5 轉換墊片 348
20.6 複合式墊片概念 350
20.6.1 訪問墊片 351
20.6.2 返回值生命期 352
20.6.3 泛化的類型操縱 354
20.6.4 效率方面的考慮 356
20.7 名字空間和Koenig查找 357
20.8 為何不使用traits 359
20.9 結構一致性 360
20.10 打破巨石 362
20.11 墊片:尾聲 363
第21章 飾面 365
21.1 輕量級RAII 366
21.2 將數據和操作綁定在一起 367
21.2.1 pod_veneer 368
21.2.2 創建日誌訊息 370
21.2.3 減少浪費 371
21.2.4 類型安全的訊息類 372
21.3 “擦亮”飾面概念 374
21.4 飾面:尾聲 376
第22章 螺栓 377
22.1 添加功能 377
22.2 皮膚選擇 378
22.3 非虛重寫 379
22.4 巧用作用域 380
22.5 擬編譯期多態:逆反式
螺栓 383
22.6 參數化多態包裝 384
22.7 螺栓:尾聲 386
第23章 模板構造函式 387
23.1 不易察覺的開銷 389
23.2 懸掛引用 389
23.3 模板構造函式特化 391
23.4 實參代理 392
23.5 明確實參的範疇 394
23.6 模板構造函式:尾聲 395
第五部分 操作符 396
第24章 operator bool() 398
24.1 operator int() const 398
24.2 operator void *() const 399
24.3 operator bool() const 400
24.4 operator !() const 401
24.5 operator boolean const *()
const 401
24.6 operator int boolean::*()
const 402
24.7 在現實世界中操作 402
24.8 operator! 407
第25章 快速、非侵入性的字元串
拼接 408
25.1 fast_string_concatenator 409
25.1.1 與用戶自定義的字元
串類協同工作 409
25.1.2 將“拼接子”串起來 410
25.1.3 fast_string_concatenator
類 411
25.1.4 內部實現 413
25.2 性能 417
25.3 與其他字元串類協作 420
25.3.1 整合進標準庫中 420
25.3.2 整合進可改動的現存
類中 420
25.3.3 與不可更改的類互
操作 420
25.4 拼接提示 421
25.5 病態括弧 422
25.6 標準化 423
第26章 你的地址是什麼 424
26.1 無法得到真實的地址 424
26.1.1 STL式元素存放 424
26.1.2 ATL外覆類和CAdapt 425
26.1.3 獲取真實的地址 426
26.2 在轉換過程中發生了什麼 427
26.3 我們返回什麼 429
26.4 你的地址是什麼:尾聲 431
第27章 下標索引操作符 434
27.1 指針轉換與下標索引操作符 434
27.1.1 選擇隱式轉換操作符 436
27.1.2 選擇下標索引操作符 437
27.2 錯誤處理 437
27.3 返回值 439
第28章 增量操作符 441
28.1 缺少後置式操作符 442
28.2 效率 443
第29章 算術類型 446
29.1 類定義 446
29.2 預設構造 447
29.3 初始化(值構造) 447
29.4 拷貝構造函式 450
29.5 賦值 450
29.6 算術操作符 451
29.7 比較操作符 452
29.8 訪問值 452
29.9 sinteger64 453
29.10 截斷、提升以及布爾測試 453
29.10.1 截斷 453
29.10.2 提升 455
29.10.3 布爾測試 455
29.11 算術類型:尾聲 456
第30章 短路 458
第六部分 擴展C++ 460
第31章 返回值生命期 461
31.1 返回值生命期問題分類 461
31.1.1 局部變數 462
31.1.2 局部靜態對象 462
31.1.3 析構後指針
(Postdestruction Pointers) 462
31.2 為何按引用返回 462
31.3 解決方案1:
integer_to_string 462
31.4 解決方案2——TSS 465
31.4.1 --declspec(thread) 466
31.4.2 Win32 TLS 466
31.4.3 平台無關的API 469
31.4.4 RVL 470
31.5 解決方案3——擴展RVL 470
31.5.1 解決執行緒內的RVL-LS問題 471
31.5.2 RVL 472
31.6 解決方案4——靜態數組大
小決議 472
31.7 解決方案5——轉換墊片 474
31.8 性能 476
31.9 RVL:垃圾收集的大勝利 477
31.10 可能的套用 478
31.11 返回值生命期:尾聲 478
第32章 記憶體 479
32.1 記憶體分類 479
32.1.1 棧和靜態記憶體 479
32.1.2 棧擴張 480
32.1.3 堆記憶體 481
32.2 兩者之間的折衷 481
32.2.1 alloca() 482
32.2.2 VLA 483
32.2.3 auto_buffer 483
32.2.4 使用auto_buffer 486
32.2.5 EBO,在哪裡 487
32.2.6 性能 488
32.2.7 堆、棧以及其他 490
32.2.8 pod_vector 491
32.3 配置器 493
32.3.1 函式指針 493
32.3.2 配置器接口 494
32.3.3 每庫初始化(Per-library
Initialization) 495
32.3.4 每調用指定(Per-Call
Specification) 496
32.4 記憶體:尾聲 496
第33章 多維數組 497
33.1 激活下標索引操作符 498
33.2 運行時確定大小 499
33.2.1 可變長數組 499
33.2.2 vector< ... vector
... > 500
33.2.3 boost::multi_array 501
33.2.4 fixed_array_1/2/3/4d 501
33.3 編譯期確定大小 505
33.3.1 boost::array 506
33.3.2 static_array_1/2/3/4d 506
33.4 塊訪問 508
33.4.1 使用std::fill_n() 509
33.4.2 array_size墊片 510
33.5 性能 512
33.5.1 運行期確定大小 513
33.5.2 編譯期確定大小 514
33.6 多維數組:尾聲 515
第34章 仿函式和區間 516
34.1 語法混亂 516
34.2 for_all() 517
34.2.1 數組 518
34.2.2 命名 518
34.3 局部仿函式 520
34.3.1 手寫循環 520
34.3.2 自定義仿函式 521
34.3.3 內嵌的仿函式 521
34.3.4 溫和一些 523
34.3.5 泛化的仿函式:類型隧
道(Type Tunneling) 524
34.3.6 再進一步,走得太
遠了 526
34.3.7 局部仿函式和回調
API 527
34.4 區間 529
34.4.1 區間概念 529
34.4.2 概念性區間 531
34.4.3 可疊代區間 533
34.4.4 區間算法和標籤 533
34.4.5 過濾器 535
34.4.6 虛偽 536
34.5 仿函式和區間:尾聲 536
第35章 屬性 537
35.1 編譯器擴展 539
35.2 可供選擇的實現方案 539
35.2.1 將屬性的實現分門
別類 540
35.2.2 EMO 540
35.3 欄位屬性 541
35.3.1 field_property_get 541
35.3.2 field_property_set 545
35.3.3 內置式欄位屬性:
尾聲 546
35.3.4 field_property_get_
external 546
35.3.5 field_property_set_
external 547
35.3.6 Hack掉 547
35.4 方法屬性 548
35.4.1 method_property_get 548
35.4.2 method_property_set 555
35.4.3 method_property_getset 555
35.4.4 謹防無限循環 557
35.4.5 method_property_get
_external 558
35.4.6 method_property_set
_external 561
35.4.7 method_property_getset
_external 562
35.5 靜態屬性 564
35.5.1 靜態欄位屬性 564
35.5.2 內置式靜態方法屬性 564
35.5.3 外置式靜態方法屬性 566
35.6 虛屬性 567
35.7 屬性的使用 568
35.7.1 泛化性 568
35.7.2 錯誤診斷中的類型
替換 569
35.8 屬性:尾聲 570
附錄A 編譯器和庫 572
A.1 編譯器 572
A.2 庫 573
A.2.1 Boost 574
A.2.2 STLSoft 574
A.2.3 其他庫 574
A.3 其他資源 575
A.3.1 期刊 575
A.3.2 其他語言 575
A.3.3 新聞組 576
附錄B “謙虛點,別驕傲” 577
B.1 操作符重載 577
B.2 後悔DRY 579
B.3 偏執式編程 579
B.4 精神錯亂 580
附錄C Arturius 582
附錄D 隨書光碟 583
尾聲 584
參考書目 585