右值參考、移動語意與完美轉發練習題 (Practice - Rvalue References, Move Semantics, and Perfect Forwarding)

Question 1 - std::move 的本質 [recall]

同事在 code review 說:「這裡呼叫 std::move,執行期會把資料搬到新物件。」請指出這句話的錯誤,並說明 std::movestd::forward 各自真正做的事。

Question 2 - const 成員的 move 陷阱 [application]

你寫了 explicit Annotation(const std::string text) : valuemove(text) {},程式編譯、執行都正常,但效能量測顯示成員初始化仍是複製。為什麼?該怎麼修正?

Question 3 - universal reference 判別 [recall]

請說明一個 type&& 宣告要成為 universal reference 必須同時滿足的兩個條件,並各舉一個「看似 T&& 卻是 rvalue reference」的反例。

Question 4 - push_back vs emplace_back [recall]

std::vectorpush_back(T&& x)emplace_back(Args&&... args) 都寫在模板類別裡且形式都是 type&&,為何前者是 rvalue reference、後者是 universal reference?

Question 5 - move 與 forward 的分工 [recall]

寫一個類別同時有 Widget(Widget&& rhs)template<typename T> void setName(T&& newName),轉發它們的參數時分別該用 std::move 還是 std::forward?若同一參考在函式內要使用多次呢?

Question 6 - return std::move 與 RVO [analysis]

為了「幫編譯器最佳化」,同事把 Widget makeWidget() { Widget w; ...; return w; } 改成 return std::move(w);。請分析這為何反而更糟:RVO 的兩個成立條件是什麼?編譯器若不做 copy elision,標準又規定了什麼?

Question 7 - 最貪婪的函式 [recall]

為什麼說「接受 universal reference 的函式是 C++ 中最貪婪的函式」?這對「把 universal reference 函式與其他函式放在同一組重載」有什麼影響?

Question 8 - 消失的 copy 建構子 [application]

Person 有 perfect-forwarding ctor template<typename T> explicit Person(T&& n) 與編譯器生成的 copy/move ctor。Person p("Nancy"); auto cloneOfP(p); 竟然編譯失敗;但改成 const Person cp("Nancy"); auto cloneOfP(cp); 又成功。請解釋兩者差異。

Question 9 - 五種替代方案 [recall]

Item 27 提供哪五種「在 universal reference 上重載」的替代方案?哪些支援 perfect forwarding?哪個是 constructor 情境的唯一可行解?

Question 10 - enable_if 條件演進 [analysis]

Person 的 perfect-forwarding ctor 撰寫 std::enable_if 條件時,為何 !std::is_same<Person, T> 不夠?為何加了 std::decay_t 還不夠、最後要用 std::is_base_of?完整版還要再排除什麼?

Question 11 - reference collapsing 規則 [recall]

使用者能否宣告 reference to reference?請寫出 reference collapsing 的塌縮規則,並列出它發生的四種 context。

Question 12 - move 的悲觀假設 [recall]

Item 29 要你假設 move 操作「不存在、不便宜、不會被使用」。請各舉一個具體情境(提示:C++98 舊型別、std::array / SSO、noexcept),並說明何時可以不必悲觀。

Question 13 - 轉發失敗五大案例 [recall]

請列出完美轉發的五大失敗案例,並說明「轉發失敗」的統一定義與兩種根本模式。

Question 14 - 轉發失敗的修復 [application]

void f(const std::vector<int>& v); 直接呼叫 f({1,2,3}) 成功,但 fwd({1,2,3}) 編譯失敗;fwdMinVals(僅宣告的 static const std::size_t MinVals = 28;)則編譯成功卻連結失敗。請分別解釋原因並給出修復方式。