std::move 与 std::forward
使用 std::move 将左值转换为右值,并使用 std::forward 保留值类别
std::move 与 std::forward 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。
两个近亲,各司其职
std::move 和 std::forward 都是编译期类型转换。它们看起来相似,但解决的是不同的问题。
std::move:始终转换为右值
std::move(x) 无条件地将 x 转换为右值引用。接收方函数随后就可以窃取它的资源。
std::string s = "Hello";
std::string t = std::move(s); // move-constructs t from s
// s is now in a valid-but-unspecified state何时使用 move
请在以下场景中使用 std::move:
- 移动构造函数和移动赋值运算符
- 当您想强制移动时返回局部变量(很少需要这样做——RVO 通常会生效)
- 将不再需要的局部对象传给接收函数
std::move 的实现
它只是伪装成其他形式的 static_cast:
template <typename T>
typename std::remove_reference<T>::type&& move(T&& t) noexcept {
return static_cast<typename std::remove_reference<T>::type&&>(t);
}std::forward:保留值类别
在使用转发引用(T&&)的模板中,std::forward<T>(x) 会将 x 转换回其原始值类别(左值或右值)。它用于完美转发。
template <typename T>
void wrapper(T&& arg) {
target(std::forward<T>(arg)); // forwards as lvalue or rvalue depending on T
}为什么需要转发
在模板内部,参数拥有一个名称,因此会成为左值,即使调用者传入的是右值。std::forward 可以恢复原始值类别。
不使用 std::forward
如果不使用 forward,所有参数都会在 wrapper 内部作为左值传递,从而无法实现调用者所希望的移动语义。
template <typename T>
void wrapper(T&& arg) {
target(arg); // always lvalue — wrong
}始终为 forward 指定模板参数
std::forward<T> 要求显式提供模板参数。如果省略该参数,行为就会不正确。
完美转发示例
能够转发构造函数参数的工厂函数可以保留右值与左值之间的区别,从而提高效率。
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}只移动一次
每个对象最多应被移动一次。移动之后,对象处于有效但未指定的状态——通常应重新赋值或销毁它。在重新赋值之前使用已被移动的对象,可能会导致难以察觉的错误。
经验法则
快速的思维模型:
- 有一个具体类型,并希望移动它 →
std::move - 有一个模板参数,并希望保留值类别 →
std::forward<T>
快速检查
在参数为 T&& arg 的模板函数内部,如何在保留 arg 左值或右值类别的同时转发它?
回顾
std::move 无条件地将对象转换为右值——用于您想从中窃取资源的具体对象。std::forward<T> 会在通用模板内部保留值类别——用于完美转发。
常见问题解答
「std::move 与 std::forward」课时是免费的吗?
是的 — 「std::move 与 std::forward」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。
「std::move 与 std::forward」这节课中我会学到什么?
使用 std::move 将左值转换为右值,并使用 std::forward 保留值类别 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C++ Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「std::move 与 std::forward」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C++ Academy 课中编写并运行代码吗?
能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 左值与右值:区别所在
- 右值引用与 && 语法
- std::move 与 std::forward
- 移动构造函数与移动赋值