關聯點
都是執行轉換(cast)的函數(函數模板),不產生任何可執行代碼。且都可以把實參轉換成右值。
std::move無條件將實參(const除外 )轉換成右值引用,std::forward 條件返回右值引用
_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept {return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}
_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {return static_cast<_Ty&&>(_Arg);
}_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");return static_cast<_Ty&&>(_Arg);
}
_EXPORT_STD template <class _Ty>
struct remove_reference {using type = _Ty;using _Const_thru_ref_type = const _Ty;
};template <class _Ty>
struct remove_reference<_Ty&> {using type = _Ty;using _Const_thru_ref_type = const _Ty&;
};template <class _Ty>
struct remove_reference<_Ty&&> {using type = _Ty;using _Const_thru_ref_type = const _Ty&&;
};_EXPORT_STD template <class _Ty>
using remove_reference_t = typename remove_reference<_Ty>::type;
先去引用,然后轉換成右值
區別
1. 用途不同
std::move
無條件將左值轉換為右值引用,表示對象資源可被“移動”。用于觸發移動構造函數或移動賦值運算符,避免深拷貝。
示例:
std::string s1 = "Hello";
std::string s2 = std::move(s1); // s1 的資源被移動到 s2,s1 不再有效
std::forward
有條件地保持值類別(左值/右值),用于完美轉發。通常與萬能引用(T&&
)配合,在泛型代碼中保持參數的原始類型。
示例:
template<typename T>
void wrapper(T&& arg) {callee(std::forward<T>(arg)); // 保持 arg 的原始值類別
}
2. 轉換條件
std::move
無論輸入是左值還是右值,始終返回右值引用。
auto rval = std::move(lval); // 無條件轉為右值
std::forward
根據模板參數T
的類型決定轉換行為:
forward<T>(arg); // 類型 T 決定結果
- 若 `T` 是左值引用(如 `int&`),返回左值引用。
- 若 `T` 是非引用或右值引用(如 `int` 或 `int&&`),返回右值引用。
3. 實現機制
std::move
** 實現**
template<typename T>
constexpr typename std::remove_reference<T>::type&& move(T&& t) noexcept {return static_cast<typename std::remove_reference<T>::type&&>(t);
}
直接通過 static_cast
將輸入轉換為右值引用。
std::forward
** 實現**
template<typename T>
constexpr T&& forward(typename std::remove_reference<T>::type& t) noexcept {return static_cast<T&&>(t);
}
根據 T
的類型推斷結果,決定返回左值或右值引用。
4. 應用場景
- 使用
std::move
的場景- 需要明確轉移對象資源所有權時(如實現移動構造函數)。
- 避免拷貝開銷,例如將局部變量移動到容器中:
std::vector<std::string> vec;
std::string s = "data";
vec.push_back(std::move(s)); // 移動而非拷貝
- 使用
std::forward
的場景- 泛型函數模板中轉發參數,保持其原始值類別:
template<typename... Args>
void emplace(Args&&... args) {container.emplace_back(std::forward<Args>(args)...); // 完美轉發參數包
}
總結
特性 | std::move | std::forward |
---|---|---|
目的 | 強制轉為右值,觸發移動語義 | 保持參數原始值類別,完美轉發 |
轉換條件 | 無條件 | 依賴模板參數 T |
典型應用 | 移動構造函數、避免拷貝 | 泛型代碼中的參數轉發 |
參數類型 | 接受任意類型 | 通常與萬能引用 T&& 配合使用 |
補充:
//拷貝構造
MyStruct(const Mystruct &)
{
}
//移動構造
Mystruct( Mystruct &&) // 無const
{
}
萬能引用:
T&&