當你第一次學習move語義和完美轉發時,它們看起來很直截了當:
* __Move語義__使編譯器能夠把昂貴的拷貝操作替換為代價較小的move操作。 和拷貝構造函數以及拷貝賦值運算符能賦予你控制拷貝對象的能力一樣,move構造函數以及move賦值運算符提供給你對move語義的控制。Move語義使得move-only類型的創建成為可能,比如說`std::unique_ptr`,`std::future`以及`std::thread`.
* __完美轉發__讓我們可以寫出接受任意參數的函數模板,并且將之轉發到其他的函數,使得target函數接受的參數和forwarding函數接受的參數相同。
右值引用對于這兩個看起來毫無關系的概念來說,就像是粘合兩者的膠水。它作為潛在的語言機制,為move語義和完美轉發的實現提供支持。
你對這些特性越有經驗,你就越發現你對它們的第一印象就像是剛剛發現了冰山一角。move語義,完美轉發以及右值引用跟它們看起來比有細微差別,比如說,move語義并不move任何東西,完美轉發是不完美的。move操作的代價并不總是比拷貝低;就算當它們確實代價底時,也沒有達到你想象的低的程度;它也并不總是在move有效的上下文中被調用。結構`type&&`并不一定總是代表一個右值引用。
不管你怎么去探索這些特性,看起來它們總是還有一些你還沒注意到的地方。幸運的是,它們的知識不是永無止境的。本章會帶你直達基礎。看完本章節,C++ 11的這部分內容對你來說就變得栩栩如生。比如說,你就會知道std::move和std::forward的常見用法,帶有迷惑性的`type&&`用法對你來說變得很平常。你也會理解move操作的各種讓人感到奇怪的表現的原因.這些都會水到渠成。到那時,你又會回到了起點,因為move語義,完美轉發,以及右值引用又一次看起來是那么的直截了當。但這次,它們(直截了當)的狀態會一直保持下去。
在本章的所有Item中,你必須要牢記一點,作為函數的參數,永遠是一個左值,即使它(在函數的參數列表中)的類型是一個右值引用。例如:
```cpp
void f(Widget&& w);
```
參數w是一個左值,即使它的類型是一個對Widget的右值引用。(如果你對此感到不理解,請重新回顧一下第2頁(原文的頁碼 --不負責任的譯者說)所講的左值與右值的概覽內容)
- 出版者的忠告
- 致謝
- 簡介
- 第一章 類型推導
- 條款1:理解模板類型推導
- 條款2:理解auto類型推導
- 條款3:理解decltype
- 條款4:知道如何查看類型推導
- 第二章 auto關鍵字
- 條款5:優先使用auto而非顯式類型聲明
- 條款6:當auto推導出非預期類型時應當使用顯式的類型初始化
- 第三章 使用現代C++
- 條款7:創建對象時區分()和{}
- 條款8:優先使用nullptr而不是0或者NULL
- 條款9:優先使用聲明別名而不是typedef
- 條款10:優先使用作用域限制的enmu而不是無作用域的enum
- 條款11:優先使用delete關鍵字刪除函數而不是private卻又不實現的函數
- 條款12:使用override關鍵字聲明覆蓋的函數
- 條款13:優先使用const_iterator而不是iterator
- 條款14:使用noexcept修飾不想拋出異常的函數
- 條款15:盡可能的使用constexpr
- 條款16:保證const成員函數線程安全
- 條款17:理解特殊成員函數的生成
- 第四章 智能指針
- 條款18:使用std::unique_ptr管理獨占資源
- 條款19:使用std::shared_ptr管理共享資源
- 條款20:在std::shared_ptr類似指針可以懸掛時使用std::weak_ptr
- 條款21:優先使用std::make_unique和std::make_shared而不是直接使用new
- 條款22:當使用Pimpl的時候在實現文件中定義特殊的成員函數
- 第五章 右值引用、移動語義和完美轉發
- 條款23:理解std::move和std::forward
- 條款24:區分通用引用和右值引用
- 條款25:在右值引用上使用std::move 在通用引用上使用std::forward
- 條款26:避免在通用引用上重定義函數
- 條款27:熟悉通用引用上重定義函數的其他選擇
- 條款28:理解引用折疊
- 條款29:假定移動操作不存在,不廉價,不使用
- 條款30:熟悉完美轉發和失敗的情況
- 第六章 Lambda表達式
- 條款31:避免默認的參數捕捉
- 條款32:使用init捕捉來移動對象到閉包
- 條款33:在auto&&參數上使用decltype當std::forward auto&&參數
- 條款34:優先使用lambda而不是std::bind
- 第七章 并發API
- 條款35:優先使用task-based而不是thread-based
- 條款36:當異步是必要的時聲明std::launch::async
- 條款37:使得std::thread在所有的路徑下無法join
- 條款38:注意線程句柄析構的行為
- 條款39:考慮在一次性事件通信上void的特性
- 條款40:在并發時使用std::atomic 在特殊內存上使用volatile
- 第八章 改進
- 條款41:考慮對拷貝參數按值傳遞移動廉價,那就盡量拷貝
- 條款42:考慮使用emplace代替insert