关联点
都是执行转换(cast)的函数(函数模板),不产生任何可执行代码。且都可以把实参转换成右值。
std::move无条件将实参(const除外 )转换成右值引用,std::forward 条件返回右值引用
python
_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);
}
python
_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);
}
python
_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
无条件将左值转换为右值引用,表示对象资源可被"移动"。用于触发移动构造函数或移动赋值运算符,避免深拷贝。
示例:
cpp
std::string s1 = "Hello";
std::string s2 = std::move(s1); // s1 的资源被移动到 s2,s1 不再有效
std::forward
有条件地保持值类别(左值/右值),用于完美转发。通常与万能引用(T&&
)配合,在泛型代码中保持参数的原始类型。
示例:
cpp
template<typename T>
void wrapper(T&& arg) {
callee(std::forward<T>(arg)); // 保持 arg 的原始值类别
}
2. 转换条件
std::move
无论输入是左值还是右值,始终返回右值引用。
cpp
auto rval = std::move(lval); // 无条件转为右值
std::forward
根据模板参数T
的类型决定转换行为:
cpp
forward<T>(arg); // 类型 T 决定结果
- 若 `T` 是左值引用(如 `int&`),返回左值引用。
- 若 `T` 是非引用或右值引用(如 `int` 或 `int&&`),返回右值引用。
3. 实现机制
std::move
** 实现**
cpp
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
** 实现**
cpp
template<typename T>
constexpr T&& forward(typename std::remove_reference<T>::type& t) noexcept {
return static_cast<T&&>(t);
}
根据 T
的类型推断结果,决定返回左值或右值引用。
4. 应用场景
- 使用
std::move
的场景- 需要明确转移对象资源所有权时(如实现移动构造函数)。
- 避免拷贝开销,例如将局部变量移动到容器中:
cpp
std::vector<std::string> vec;
std::string s = "data";
vec.push_back(std::move(s)); // 移动而非拷贝
- 使用
std::forward
的场景- 泛型函数模板中转发参数,保持其原始值类别:
cpp
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&&