C++11 引入右值引用,std::move 與 std::forward 是移動語義與完美轉發的核心工具。本文從定義、工作原理、引用折疊、標準庫應用四個維度深度剖析。
template
constexpr remove_reference_t&& move(T&& t) noexcept {
return static_cast&&>(t);
}
"hello"):T 推導為 string,參數類型 string&&,返回 string&&,static_cast 保持右值屬性。string s):T 推導為 string&,remove_reference 得 string,參數類型折疊為 string&,返回 string&&,static_cast 強制轉為右值引用。move 僅做類型轉換,不移動內存。它告訴編譯器:「請將此對象視為右值,啟用移動構造/賦值」。
T& &、T& &&、T&& & → T&T&& && → T&&
// 左值轉發
template
constexpr T&& forward(remove_reference_t& t) noexcept {
return static_cast(t);
}
// 右值轉發
template
constexpr T&& forward(remove_reference_t&& t) noexcept {
static_assert(!is_lvalue_reference_v);
return static_cast(t);
}
T = U&,參數類型 U&,返回 U&(折疊),保持左值屬性。T = U,參數類型 U&&,返回 U&&,保持右值屬性。forward 必須在模板函數中使用,並顯式傳遞模板參數 forward(arg) ,以便根據實參原始值類別保持值類別。
U&),右值調用第二個(參數 U&&),static_assert 禁止右值重載被左值實參匹配。
make_shared / allocate_shared
template
shared_ptr make_shared(Args&&... args) {
return allocate_shared(allocator(), forward(args)...);
}
template
shared_ptr allocate_shared(const Alloc& a, Args&&... args) {
// 內部構造對象:
::new(ptr) T(forward(args)...); // 完美轉發構造參數
}
參數包轉發:forward(args)... 將每個參數按其原始左/右值屬性轉發給構造函數,實現零開銷轉發。
| std::move | std::forward | |
|---|---|---|
| 目的 | 無條件轉右值,啟用移動 | 保持原始值類別,完美轉發 |
| 使用場景 | 明確不再使用原對象時 | 模板轉發參數給其他函數 |
| 模板參數 | 自動推導 | 必須顯式指定 forward |
| 核心機制 | static_cast | 引用折疊 + 重載解析 |
move 用於「所有權轉移」場景(如放入容器、返回局部對象)。forward 僅用於「轉發參數」的模板函數中(工廠函數、構造函數包裝器)。move(移後狀態未定義)。