# std::move 与 std::forward 的区别
面试官问"move 和 forward 有什么区别",很多人只能说出"一个是移动一个是转发"——这等于没答。这道题的关键是把"无条件 vs 有条件"讲清楚,再说明各自的使用场景和底层机制。
# 简要回答
std::move 是无条件转换:不管传进来的是左值还是右值,一律转成右值引用,语义是"我不要了,你拿走"。
std::forward 是有条件转换:只有当原始参数是右值时才转成右值引用,左值还是左值。语义是"你给我什么类型,我原封不动传下去"。
两者本质都是 static_cast,不生成任何代码,纯粹是编译期的类型转换。
# 详细回答
std::move 的机制
实现就一行:static_cast<remove_reference_t<T>&&>(t)。不管 T 是什么,先去掉引用,再加上 &&,结果一定是右值引用。它不"移动"任何东西,只是告诉编译器"这个对象可以被移动",真正的移动发生在移动构造/移动赋值里。
使用后原对象处于"有效但未指定"状态(moved-from state),只能析构或重新赋值,不能假设它还有原来的值。
std::forward 的机制
依赖两个规则配合工作:万能引用(T&& 在模板中)+ 引用折叠。当传入左值时 T 推导为 X&,X& && 折叠为 X&,forward 返回左值引用;当传入右值时 T 推导为 X,X&& 就是右值引用,forward 返回右值引用。
所以 forward 只在模板函数中有意义——非模板函数没有参数推导,也就没有"保持原始值类别"这回事。
核心对比
| 维度 | std::move | std::forward |
|---|---|---|
| 转换方式 | 无条件转右值引用 | 有条件,保持原始值类别 |
| 使用场景 | 明确要转移所有权时 | 模板中完美转发参数时 |
| 依赖条件 | 无 | 万能引用 + 引用折叠 |
| 本质 | static_cast 去引用加&& | static_cast 配合推导结果 |

# 知识拓展
Q:对 const 对象 move 会怎样?
move 本身不报错,但移动构造/赋值通常接收的是非 const 右值引用(T&&),const 右值引用匹配不上,就退化成拷贝。所以对 const 对象 move 等于白 move,性能没有任何提升。
Q:forward 为什么只能用在模板里?
因为 forward 的"有条件"依赖模板参数推导的结果。非模板函数的参数类型是写死的,没有推导过程,也就没有"原始值类别"可以保持。
Q:move 之后还能用原对象吗?
标准说 moved-from 对象处于"有效但未指定"状态。实践中只能做两件事:析构、重新赋值。不能假设它还持有原来的资源。标准库容器 move 后通常变成空容器,但这不是标准保证的。
Q:什么时候该用 move,什么时候该用 forward?
规则很简单:如果你明确知道这个对象不再需要了,用 move;如果你在模板里接收参数并要传给下一层函数,用 forward。两者不能混用——在模板转发场景用 move 会把左值也强制变成右值,破坏调用者的预期。
评论
验证登录状态...