系統程式設計師的 C++

std::move 與 std::forward

這兩個函式庫函式看起來像在做什麼了不起的事,但每一個其實都只是個精心挑選的轉型——它們本身不產生任何機器碼。std::move(x) 說「我用完 x 了,把它當作可拋棄,好讓移動發生」,而 std::forward<T>(x) 說「把 x 往下傳,並完整保留呼叫者給我的究竟是暫存物件還是具名物件」。兩者都在引導要選用哪個多載——複製還是移動。

std::move 較單純:它無條件地把引數轉型為右值參考。那個轉型不移動任何東西;它只是讓引數有資格繫結到移動建構子或移動賦值,而非複製。若你有個不再需要的具名區域變數,std::move(local) 就讓下一個操作得以掠奪它。std::forward 用於通用的「轉發」程式碼。當模板以 T&&(轉發參考,forwarding reference)接收引數時,語言允許那一個參數同時繫結到左值與右值;std::forward<T>(arg) 在往下傳遞時把它重新轉型回原本的值類別(value category),於是暫存物件仍可移動、具名物件仍可複製。這個模式——「完美轉發」——正是 make_unique 與 emplace_back 把你的建構子引數原封不動傳過去的方法。

為何重要:兩者合力讓函式庫作者避免無謂的複製,並寫出一個對暫存物件與左值都做對事的通用函式,而不必寫多個分開的多載。誠實的陷阱:呼叫 std::move(x) 之後你必須把 x 當成已被榨乾(有效但未指定);std::forward 只有在參數是真正的轉發參考 T&& 且 T 為推導而來的函式內才正確——用在別處,或對 const 物件用 std::move,都會悄悄地什麼有用的事都沒做,於是你又退回了複製。

template<class... A> auto make(A&&... a) { return T(std::forward<A>(a)...); } // 轉發每個引數並保留其左值/右值身分

完美轉發:傳入的暫存物件仍可移動;具名左值仍只可複製——恰如呼叫者的本意。

對 const 物件用 std::move 是個陷阱:它轉型成 const T&&,而非 const 的移動建構子無法繫結到它,於是改選複製建構子。你得到一次無聲的複製卻沒有任何錯誤——移動要求來源是可修改的。

又稱
perfect forwarding完美轉發