速查表 (Quick Reference)

全書 42 個 Item 的核心規則速查。每章一節:先列該章的關鍵公式/判斷表,再以「概念 | 規則 | 筆記連結」整理所有速查規則。詳細推導與陷阱請點入各筆記;面試陷阱另見 面試陷阱題,學習路線見 學習地圖

導論 → 術語與慣例

概念 規則 筆記連結
Parameter 恆為 lvalue 所有函式 parameter 都是 lvalue,即使型別是 rvalue reference(如 Widget&& rhs);能取位址的 expression 通常是 lvalue 術語與慣例
Copy 用語 以同型別物件初始化的新物件一律稱 copy,不論經 copy 或 move construction 建立 術語與慣例
Exception safety 兩級保證 basic:例外後 invariant 完好、無資源洩漏;strong:例外後狀態回到呼叫前 術語與慣例
書中版本用語 書中「C++11」涵蓋 C++11 與 C++14;「C++98」涵蓋 C++98/03;寫「C++14」才專指 C++14 術語與慣例

第 1 章:型別推導 → 模板型別推導

Template Type Deduction 三情境表

Case ParamType 形式 推導規則
Case 1 T&const T&T* 忽略 expr 的 reference-ness 後模式比對求 T;constness 保留
Case 2 T&&(universal reference) lvalue 引數 → T 與 param 皆推導為 lvalue reference(T 唯一為參考的情境);rvalue 引數 → 套用 Case 1
Case 3 T(pass-by-value) 剝除 reference-ness 與頂層 const/volatile(底層 const 保留)
)。

auto 與 template 推導差異(braced-init-list)

情境 { 27 } 的推導結果
auto x = { 27 }; std::initializer_list<int>
template<typename T> void f(T);{ 27 } 編譯失敗(non-deduced context)——這是兩者唯一差異
函式 auto 回傳型別 / generic lambda 的 auto 參數 實際採 template 推導return { 1, 2, 3 }; 無法編譯

decltype 規則

對象 結果
名稱(name) 如實回報宣告型別,reference 與 const 完整保留
比名稱複雜的 lvalue 運算式(型別 T) 一律回報 T&——decltype(x)intdecltype((x))int&
decltype(auto)(C++14) 像 auto 從 initializer 推導,但改用 decltype 規則,保留 reference 與 const
概念 規則 筆記連結
Case 1:參考/指標參數 忽略 expr 的 reference-ness 後模式比對求 T;constness 保留 模板型別推導
Case 2:universal reference lvalue → T 與 param 皆為 lvalue reference;rvalue → 套 Case 1 模板型別推導
Case 3:pass-by-value 剝除 reference-ness 與頂層 const/volatile——param 是全新副本 模板型別推導
Array/Function decay 陣列與函式名稱 by-value 傳入時 decay 成指標;T& 參數則保留完整型別 模板型別推導
auto 推導本質 auto 推導=template 推導:auto 扮演 T、type specifier 扮演 ParamType,三 Case 沿用 auto 型別推導
braced initializer 特例 auto x = { 27 };std::initializer_list<int>;同樣的 {} 給 template 直接編譯失敗 auto 型別推導
回傳型別與 lambda 參數 函式 auto 回傳型別與 generic lambda 的 auto 參數採 template 推導,return {1,2,3}; 無法編譯 auto 型別推導
auto&& auto&& 是 universal reference:lvalue 初始化 → lvalue reference;rvalue → rvalue reference auto 型別推導
decltype 基本行為 對名稱如實回報宣告型別,reference 與 const 完整保留 decltype 規則
lvalue expression 規則 對非名稱的 lvalue 運算式(型別 T)一律回報 T&decltype((x))int& decltype 規則
decltype(auto) C++14:以 decltype 規則推導回傳型別/變數,回傳要與 c[i] 完全一致時使用;C++11 用 trailing return type decltype 規則
auto 回傳型別陷阱 只寫 auto 作回傳型別採 template 推導、剝掉 reference,int& 變 rvalue int decltype 規則
編譯期檢視型別 宣告未定義模板 TD<decltype(x)> xType; 觸發編譯錯誤,錯誤訊息必含完整推導型別 檢視推導型別
typeid 的失真 std::type_info::name 依規格以 by-value 規則處理:剝 reference 再剝頂層 cv,必然失真 檢視推導型別
執行期準確輸出 用 Boost.TypeIndex 的 type_id_with_cvr<decltype(x)>().pretty_name(),保留 cvr 修飾 檢視推導型別
工具定位 IDE/編譯錯誤/Boost.TypeIndex 都只是輔助;理解 Items 1-3 推導規則無可取代 檢視推導型別

第 2 章:auto → 優先使用 auto

概念 規則 筆記連結
auto 強制初始化 auto 變數必須有 initializer,從語法上根絕未初始化變數 優先使用 auto
持有 closure 用 auto 持有 lambda closure:比 std::function 更小、更快、可 inline、不 heap 配置 優先使用 auto
避免 type shortcuts auto sz = v.size(); 取得精確 size_type,避免 unsigned 在 64-bit 平台截斷 優先使用 auto
range-for 遍歷 map const auto&——元素實為 pair<const Key, Value>,顯式寫錯型別每圈複製暫時物件 優先使用 auto
vector<bool> 下標 operator[] 回傳 proxy 而非 bool&;auto 接住會複製 proxy,可能懸空 → UB 顯式型別初始器慣用法
隱形 proxy 與 auto 隱形 proxy(vector<bool>::reference、expression templates)不應被 auto 直接推導;顯性 proxy(智慧指標)相容 顯式型別初始器慣用法
顯式型別初始器慣用法 不放棄 auto,改寫 auto x = static_cast<T>(expr); 強迫推導出 T 顯式型別初始器慣用法
刻意轉型的表達 刻意縮窄轉換(double→float/int)用 static_cast 明示意圖,優於隱式轉換 顯式型別初始器慣用法

第 3 章:邁向現代 C++ → 大括號初始化

() vs {} 決策表

情況 用法 結果
需禁止 narrowing、避免 most vexing parse {} Widget w{}; 呼叫建構子;Widget w(); 宣告函式
類別有 std::initializer_list 建構子 小心 {} 只要引數能轉成元素型別就強制匹配 initializer_list 版(連 copy/move 都可被劫持);需 narrowing 直接編譯錯誤、不回退
空大括號 Widget w{}; 呼叫 default constructor,非空 initializer_list;要空 list 寫 w({})w{{}}
std::vector<int> v(10, 20) vs v{10, 20} () 得 10 個 20;{} 得 2 個元素 10、20
模板內建立物件(如 make 函式) 預設 () {}() 語意可能完全不同,模板作者無從得知呼叫者意圖
概念 規則 筆記連結
{} 三大優點 適用範圍最廣、禁止 narrowing conversion、免疫 most vexing parse 大括號初始化
initializer_list 劫持 引數有任何辦法轉成元素型別時 {} 強制匹配 initializer_list 建構子;narrowing 直接編譯錯誤不回退 大括號初始化
null pointer 表示法 一律用 nullptr;0 是 int、NULL 是實作定義整數型別,都沒有指標型別 nullptr 用法
nullptr 的型別 std::nullptr_t,可隱式轉換為所有 raw pointer 型別,不可視為整數 nullptr 用法
0/NULL 進 template 被推導為整數型別而非指標,轉交指標參數即編譯錯誤;nullptr 推導為 nullptr_t 沒問題 nullptr 用法
typedef vs using 一律優先 alias declaration(using X = ...):與 typedef 等價但可模板化為 alias template 別名宣告
模板內巢狀 typedef X<T>::type 是 dependent type 須加 typename;alias template 不需要也不允許 別名宣告
C++14 type traits std::transformation_t<T>(如 std::remove_reference_t<T>)取代 typename std::...<T>::type 別名宣告
scoped enum 作用域 unscoped enum 列舉子洩漏到外層 scope;enum class 列舉子需 Color::white 存取 scoped enum 規則
scoped enum 轉換 無任何隱含轉換,轉整數/浮點必須 static_cast;unscoped enum 隱含轉整數再轉浮點 scoped enum 規則
前向宣告 scoped enum 永遠可前向宣告;unscoped enum 須指定底層型別才可以 scoped enum 規則
禁止複製 C++11 一律 = delete 標記 copy 操作並放 public 區段,取代 private 不定義手法 deleted functions 用法
deleted 適用範圍 任何函式都可 = delete:member、non-member 與 template instantiations deleted functions 用法
= delete 與重載 deleted 函式仍參與 overload resolution,被選中即編譯錯誤——可過濾隱含轉換 deleted functions 用法
override 宣告 所有覆寫 base virtual 函式的 derived 函式一律加 override,讓「想覆寫卻沒覆寫」變編譯錯誤 override 宣告
覆寫六大條件 base virtual、同名、同參數型別、同 constness、回傳/例外規格相容、同 reference qualifier override 宣告
Reference qualifiers 成員函式尾端 & / && 限定 *this 為 lvalue / rvalue,rvalue 版可 std::move 移出成員 override 宣告
const_iterator 優先 不需修改元素就用 const_iterator;C++11 起用成員 cbegin()/cend() const_iterator 用法
泛型 begin/end 最大化泛型程式碼用 non-member begin/end/cbegin,支援內建陣列;non-member cbegin 是 C++14 才有 const_iterator 用法
noexcept 與介面 noexcept 是函式介面的一部分,呼叫端會依賴;事後移除會破壞 client code noexcept 宣告
noexcept 與 move 容器擴容「move if you can, copy if you must」:僅當 move ctor 為 noexcept 才以 move 取代 copy noexcept 宣告
預設隱含 noexcept destructor 與 operator delete 預設隱含 noexcept;多數函式 exception-neutral 不該宣告 noexcept 宣告
constexpr 物件 一定是 const 且以編譯期已知值初始化;const 不保證編譯期已知 constexpr 用法
constexpr 函式 引數全為編譯期常量 → 編譯期結果;含執行期值 → 普通函式,一份程式碼兩種模式 constexpr 用法
constexpr 介面承諾 constexpr 是介面的一部分,事後移除會破壞依賴編譯期常量的 client code constexpr 用法
const 與執行緒安全 const 成員函式預設會被多執行緒並行呼叫,必須 thread safe(mutable 成員可能寫入) const 與執行緒安全
atomic vs mutex 選擇 單一變數/記憶體位置用 std::atomic(通常較便宜);兩個以上變數作為單位操作用 std::mutex const 與執行緒安全
mutable 同步成員 std::mutex 須宣告 mutable 才能在 const 成員函式內 lock/unlock;兩者皆 move-only const 與執行緒安全
Move 生成三條件 move 操作只在類別未宣告任何 copy 操作、move 操作、destructor 三者時才自動生成 特殊成員函式生成
宣告 move 對 copy 影響 宣告任一 move 操作 → 兩個 copy 操作被 =delete;宣告 copy → move 不生成 特殊成員函式生成
Destructor 副作用 宣告 destructor 抑制 move 生成(copy 仍生成但已 deprecated);多型基底用 virtual ~Base() = default 加四個 = default 特殊成員函式生成
成員模板不抑制生成 member function template 永不抑制特殊成員函式生成,即使可實例化出相同簽章 特殊成員函式生成

第 4 章:智慧指標 → unique_ptr

Smart Pointer 選型表

需求 選擇 成本
專屬所有權(預設首選、工廠回傳) std::unique_ptr 預設 deleter 下與 raw pointer 同大小同指令;move-only
共享所有權 std::shared_ptr raw pointer 的 2 倍大(object ptr + control block ptr),計數為 atomic 操作
shared_ptr-like 但可能懸空(cache、observer、打破 cycle) std::weak_ptr 與 shared_ptr 同大小、共用 control block、操作 weak count

make 函式優缺點

面向 內容
優點 消除型別重複(DRY)、提升 exception safety;make_shared 單次配置更小更快
不能用 需要 custom deleter 或 braced initializer {} 時只能直接 new
shared_ptr 不宜 類別自訂 operator new/delete;大物件搭配長壽 weak_ptr(整塊記憶體要等 weak count 歸零才釋放)
概念 規則 筆記連結
預設智慧指標選擇 優先 std::unique_ptr:預設 deleter 下與 raw pointer 同大小同指令,體現 exclusive ownership unique_ptr 專屬所有權
move-only 語意 unique_ptr 不可複製;move 轉移所有權且來源設為 null unique_ptr 專屬所有權
custom deleter 大小 deleter 是型別的第二個模板引數;無捕獲 lambda 零開銷(首選),function pointer 增為兩個 word unique_ptr 專屬所有權
工廠函式回傳型別 回傳 unique_ptr:呼叫者可輕鬆升級為 shared_ptr,反向轉換不存在 unique_ptr 專屬所有權
shared_ptr 成本 2 倍大小、reference count 增減為 atomic 操作;move 不動計數、比 copy 快 shared_ptr 共享所有權
Control block 建立規則 make_shared、從 unique_ptr 或 raw pointer 建構 → 新 control block;從 shared_ptr/weak_ptr 建構 → 沿用 shared_ptr 共享所有權
Custom deleter 設計 deleter 型別不屬於 shared_ptr 型別(存於 control block),不同 deleter 的 shared_ptr<T> 仍同型別 shared_ptr 共享所有權
Raw pointer 禁忌 避免用 raw pointer 變數建構 shared_ptr(重複 control block → 重複 delete → UB);必要時直接傳 new 結果 shared_ptr 共享所有權
weak_ptr 本質 shared_ptr 的 augmentation:不能 dereference、不能測 null,必須先轉回 shared_ptr weak_ptr 用法
安全存取 expired() 再取值有 race condition;一律用原子操作 lock() 或 shared_ptr 建構子 weak_ptr 用法
三大使用場景 caching factory、observer lists、打破 shared_ptr cycles(回指用 weak_ptr) weak_ptr 用法
make 三大優勢 消除型別重複、例外安全;make_shared/allocate_shared 另有單次配置 make 函式
例外安全呼叫 禁止 fshared_ptr<W>(new W), g())——g( 可插在中間拋例外造成 leak;用 make 或獨立語句 make 函式
make 不能用的情況 custom deleter 或 braced initializer 時只能直接 new make 函式
make 轉發語意 make 函式內部用 () 完美轉發:make_unique<vector<int>>(10, 20) 得 10 個 20,非 {10, 20} make 函式
Pimpl 特殊成員函式位置 unique_ptr pImpl 的 dtor/move/copy 一律「header 宣告、實作檔定義」(incomplete type 限制),= default 也要寫在實作檔 Pimpl Idiom 用法
Pimpl copy 支援 copy 必須手寫深拷貝:copy ctor 用 make_unique<Impl>(*rhs.pImpl)、copy assign 用 *pImpl = *rhs.pImpl Pimpl Idiom 用法
unique vs shared deleter unique_ptr 的 deleter 屬於型別(需 complete type);shared_ptr 的不屬於(Pimpl 儀式全免,但語意上獨占擁有仍應用 unique_ptr) Pimpl Idiom 用法

第 5 章:Move 語意與完美轉發 → std::move 與 std::forward

Universal Reference 成立條件

型別推導發生(template 參數或 auto&&)+ 宣告形式精確為 type&&——兩者缺一不可,否則是 rvalue reference。std::vector<T>&&const T&&、實體化後才呼叫的 push_back(T&&)不是 universal reference。

Reference Collapsing 四規則

塌縮結果
& & &
& && &
&& & &
&& && &&(唯一產生 rvalue reference 的組合)

只發生在四種 context:template instantiation、auto 型別生成、typedef/alias declaration、decltype。

std::move / std::forward 使用時機

參數種類 工具 時機
rvalue reference std::move(無條件轉型) 最後一次使用時
universal reference std::forward<T>(有條件轉型) 最後一次使用時
by-value 回傳綁在上述參考的參數 return std::move(lhs) / return std::forward<T>(frac) copy 變 move
符合 RVO 資格的區域變數 直接 return w;,勿加 std::move 加了反而阻礙 copy elision
概念 規則 筆記連結
std::move 本質 無條件 rvalue cast,本身不搬移任何東西,執行期零成本 std::move 與 std::forward
std::forward 本質 條件式轉型:僅當引數當初以 rvalue 初始化才轉為 rvalue,值類別編碼在模板參數 T std::move 與 std::forward
const 與 move 想被搬移的物件不要宣告 const:const rvalue 綁不上 move ctor,靜默退化為 copy std::move 與 std::forward
參數的值類別 具名函式參數永遠是 lvalue(即使型別是 Widget&&),轉交前必須 move/forward std::move 與 std::forward
UR 成立條件 型別推導+形式精確為 type&& 缺一不可;否則是 rvalue reference universal reference 判定
初始器決定身分 UR 以 lvalue 初始化 → lvalue reference(T 為 Widget&);rvalue → rvalue reference(T 為 Widget universal reference 判定
破格情形 std::vector<T>&&const T&&、實體化後才呼叫的 push_back(T&&) 都不是 UR universal reference 判定
move/forward 配對 rvalue reference → 無條件 std::move;universal reference → 有條件 std::forward,不可交換 move 與 forward 使用時機
最後一次使用 多次使用同一參考時,只在最後一次套 move/forward,避免物件提前被搬空 move 與 forward 使用時機
RVO 以值回傳區域變數直接 return w;;加 std::move 違反 RVO 條件,強制多一次 move move 與 forward 使用時機
UR 重載禁忌 不要對 UR 參數做重載——它幾乎對任何型別產生 exact match,吸走預期外的呼叫 避免對 universal reference 重載
Forwarding ctor vs copy ctor 對 non-const lvalue,forwarding ctor 實例化出 Person(Person&) 比 copy ctor 更佳匹配 避免對 universal reference 重載
繼承 + forwarding ctor derived 的 copy/move ctor 呼叫 base 會被 base 的 forwarding ctor 攔截 避免對 universal reference 重載
不需完美轉發時 優先改名(放棄重載)、pass by const T& 或 pass by value 取代 UR 重載 重載的替代方案
Tag dispatch 單一入口以 std::true_type/false_type 分派;判斷整數需先 std::remove_reference_t<T> 重載的替代方案
Constructor 場合 tag dispatch 被生成的 copy/move ctor 繞過,須用 std::enable_if + !is_base_of<Person, decay_t<T>> 重載的替代方案
塌縮規則 任一方為 & → 結果 &;只有 && + &&&& reference collapsing 規則
四種 context template instantiation、auto 型別生成、typedef/alias、decltype reference collapsing 規則
lvalue/rvalue 編碼 傳 lvalue 給 T&& → T 推導為 Widget&;傳 rvalue → T 為 Widget(非 reference)——std::forward 的基礎 reference collapsing 規則
泛型 move 假設 型別未知時假設 move not present, not cheap, not used;已知且穩定則查證後依賴 move 操作的現實
容器 move 複雜度 std::vector move O(1)(搬 heap 指標);std::array move O(n)(資料在物件內) move 操作的現實
SSO 與短字串 SSO 短字串存在物件內部緩衝區,move 沒有指標可搬,不比 copy 快 move 操作的現實
完美轉發失敗模式 只有兩種:模板型別推導失敗(編譯錯誤),或推導出錯誤型別 完美轉發失敗案例
五大失敗案例 braced initializers、0/NULL 空指標、僅宣告的整數 static const 成員、多載函式名/模板名、bitfields 完美轉發失敗案例
braced initializer 解法 auto il = {1,2,3};(推導為 initializer_list)再 fwd(il) 完美轉發失敗案例

第 6 章:Lambda 運算式 → 避免預設捕獲模式

Lambda Capture 決策表

情境 正確寫法
任何捕獲 避免 [&] / [=],明確列出捕獲對象
closure 可能存活超過區域變數 禁用 [&](dangling reference);明確 [&x] 至少點名依賴
member function 內用 data member [=] 捕的是 this 指標;C++14 用 init capture [divisor = divisor],C++11 先複製到區域變數
move-only 物件進 closure C++14 init capture [pw = std::move(pw)];C++11 用手寫 class 或 std::bind
static / global 變數 不可被捕獲;[=] 下 lambda 仍直接參照,closure 並非 self-contained
generic lambda 完美轉發 auto&& 參數 + std::forward<decltype(x)>(x)
概念 規則 筆記連結
預設 [&] 捕獲 closure 存活超過區域變數即 dangling reference;明確寫 [&x] 才能點名依賴 避免預設捕獲模式
預設 [=] 與 this member function 內 [=] 捕獲的是 this 指標而非 data member;物件亡則指標懸空 避免預設捕獲模式
捕獲 data member 正解 C++11 先複製到區域變數再捕獲;C++14 用 init capture [divisor = divisor] 避免預設捕獲模式
Move 物件進 closure C++14 init capture [pw = std::move(pw)];C++11 lambda 無原生 move capture init capture 用法
Init capture 的 scope = 左側是 closure class 資料成員名,右側運算式在 lambda 定義處的 scope 求值 init capture 用法
C++11 模擬 move capture 手寫 closure class,或 std::bind + lambda 以 lvalue reference(通常 const&)接收 init capture 用法
Generic lambda 完美轉發 lambda 內沒有 T 可用時,以 std::forward<decltype(param)>(param) 轉發 auto&& 參數 decltype 轉發
decltype 對 UR 參數 傳入 lvalue → decltype 為 lvalue reference;rvalue → rvalue reference decltype 轉發
collapsing 保證正確性 std::forward<Widget&&>&&+&& 摺疊後與 std::forward<Widget> 實例化完全相同 decltype 轉發
Lambda vs std::bind 一律優先 lambda:更可讀、更有表達力、可能更快(易 inline);C++14 起 bind 無合理用例 lambda 優於 std::bind
bind 引數求值時機 傳給 std::bind 的運算式當下立即求值存入 bind object;延遲求值須巢狀 bind lambda 優於 std::bind
bind 儲存/傳遞規則 引數一律以值儲存(std::ref 才是參考);呼叫時引數一律以參考傳遞 lambda 優於 std::bind

第 7 章:並行 API → task-based 優先

std::async Launch Policy 表

Policy 行為
std::launch::async 保證在另一條執行緒非同步執行
std::launch::deferred 僅在對 future 呼叫 get/wait 時於呼叫者執行緒同步執行;從未呼叫則永不執行
預設(async | deferred 的 OR 組合) 由執行期系統決定,不保證併發wait_for 迴圈可能永不終止
偵測 deferred fut.wait_for(0s) == std::future_status::deferred

Thread / Future Destructor 行為表

Handle 解構行為
joinable std::thread std::terminate(程式終止)
unjoinable std::thread(預設建構、被 move 走、已 join、已 detach) 安全
一般 future 只銷毀資料成員、遞減 shared state 參考計數;不 join、不 detach、不執行任務
來自 std::async + launch::async + 最後一個指涉的 future 阻塞至任務完成(隱含 join),永不終止程式
packaged_task / promise 建立的 future 一律正常行為;join/detach 由操作底層 std::thread 的程式碼決定

atomic vs volatile 對照表

面向 std::atomic volatile
用途 多執行緒並行共享資料 特殊記憶體(memory-mapped I/O)
原子性 所有成員函式(含 RMW)保證原子 無——同時讀寫是 data race → UB
重排限制 預設 sequential consistency
redundant loads / dead stores 可被優化 禁止優化
合用 特殊記憶體又被多執行緒存取:volatile std::atomic<T> 同左
概念 規則 筆記連結
非同步預設寫法 優先 std::async(task-based)而非 std::thread;future 的 get() 可取回傳值與例外 task-based 優先
std::thread 例外行為 thread 上的函式丟例外 → std::terminate;建構時執行緒耗盡丟 std::system_error task-based 優先
直接用 thread 的時機 僅限需要 native_handle()(priority/affinity)、自行最佳化 thread 用量、自建 thread pool task-based 優先
async 預設 policy async | deferred OR 組合,由執行期系統決定,不保證併發 std::launch::async 指定
deferred 執行時機 僅在 get/wait 時於呼叫者 thread 同步執行;從未呼叫則永不執行 std::launch::async 指定
保證真正非同步 必須併發時明確傳 std::launch::async,或用完美轉發包裝的 reallyAsync std::launch::async 指定
joinable thread 解構 直接 std::terminate;用 RAII 物件保證所有離開路徑上皆 unjoinable thread unjoinable 原則
unjoinable 四情況 預設建構、被 move 走、已 join、已 detach;run to completion 仍是 joinable thread unjoinable 原則
thread 成員宣告順序 std::thread 資料成員宣告在類別最後——建構後可能立即執行 thread unjoinable 原則
future 解構正常行為 只銷毀資料成員並遞減 shared state 參考計數,不 join/detach/執行任務 thread handle 解構
解構阻塞三條件 shared state 來自 std::async + policy 為 launch::async + 最後一個指涉的 future → 阻塞至完成 thread handle 解構
thread vs future 對比 joinable thread 解構 → terminate;future 解構永不終止程式,最多阻塞 thread handle 解構
一次性事件通訊 std::promise<void> + std::future<void>:免 mutex、免 spurious wakeup、真正阻塞 void future 事件通訊
condvar 方案缺陷 需多餘 mutex、notify 先於 wait 造成永久等待、需 lambda 防 spurious wakeup void future 事件通訊
多個反應任務 future::share() 取得 shared_future,每條反應執行緒以傳值捕獲自己的拷貝 void future 事件通訊
std::atomic 用途 多執行緒共享資料不用 mutex 時:所有成員函式原子、預設 sequential consistency 限制重排 atomic 與 volatile
volatile 用途 專用於特殊記憶體:禁止優化 redundant loads 與 dead stores,與執行緒安全無關 atomic 與 volatile
多執行緒下的 volatile 同時讀寫 volatile 是 data race → UB;兩執行緒各 ++ 一次 volatile int 可能得 1,atomic 必為 2 atomic 與 volatile

第 8 章:微調 → 值傳遞

Pass-by-Value 四條件

# 條件
1 copyable(move-only 型別應寫單一 rvalue reference overload)
2 cheap to move(如 SSO 字串的 move 不便宜)
3 always copied(不會有條件地不複製)
4 仍需個案評估(consider)——成本恆多一次 move:lvalue = 1 copy + 1 move;rvalue = 2 moves

Emplacement 幾乎必快三條件

# 條件
1 值以建構(非指派)方式進入容器
2 引數型別異於容器元素型別
3 不會被容器當重複值拒絕
概念 規則 筆記連結
Pass by value 適用條件 copyable + cheap to move + always copied + 個案評估,四項全滿足才考慮 值傳遞
值傳遞成本 比 by-reference 恆多一次 move:lvalue = 1 copy + 1 move;rvalue = 2 moves 值傳遞
Slicing problem base class 型別參數不可值傳遞——衍生物件會被切割成 base 部分 值傳遞
Emplacement 三條件 以建構進容器+引數型別異於元素型別+不被當重複值拒絕 → 幾乎必快 emplacement 用法
push_back("literal") 成本 產生暫時 std::string:2 次建構+1 次解構;emplace_back 僅 1 次建構 emplacement 用法
explicit 建構子差異 insertion 用 copy initialization(禁 explicit);emplacement 用 direct initialization(允許 explicit,可能放行錯誤程式碼) emplacement 用法
資源管理物件入容器 先在獨立敘述建立 smart pointer,再 push_backmove(spw);勿把 new 直接丟給 emplace emplacement 用法

必背模式 → universal reference 判定

  1. T&& 不一定是 rvalue reference:型別推導發生+形式精確為 type&& 才是 universal reference → universal reference
  2. 具名參數永遠是 lvalue:rvalue reference 用 std::move、universal reference 用 std::forward,都在最後一次使用時 → move 與 forward 使用時機
  3. Reference collapsing:任一方是 & 結果就是 &,只有 &&+&& 才是 &&reference collapsing
  4. auto 與 template 推導唯一差異:braced-init-list → auto 推導為 std::initializer_list、template 直接失敗 → auto 型別推導
  5. decltype(x) 是 int、decltype((x)) 是 int&:非名稱的 lvalue 運算式一律回報 T&decltype
  6. {} 禁止 narrowing、免疫 most vexing parse,但 initializer_list 建構子會劫持重載決議 → 大括號初始化
  7. 智慧指標選型:預設 unique_ptr、共享才 shared_ptr、可能懸空用 weak_ptr → unique_ptr
  8. 優先 make_unique/make_shared;custom deleter 與 braced initializer 是唯二只能直接 new 的情況 → make 函式
  9. move 未宣告 noexcept 就不會被用:vector 擴容為保 strong guarantee 退回 copy → noexcept
  10. 宣告 destructor 或 copy 操作任一,move 就不自動生成(改用 copy,靜默變慢) → 特殊成員函式生成
  11. 避免 [=] / [&] 預設捕獲:member function 內 [=] 捕的是 this 指標;C++14 用 init capture → 避免預設捕獲模式
  12. std::async 預設不保證非同步:必須併發時明確指定 std::launch::asyncstd::launch::async