C++中std::move和std::forward的关系和区别

一、右值引用:确定可移动,用 std::move

右值引用只绑定右值------临时对象,或调用者用 std::move 显式交出的对象。形参写成 A&&,函数就可以放心地把它当作可移动对象。但这份右值性不会自动传给下一层:

cpp 复制代码
class A {};

void goo(A&& a) { std::cout << "goo(A&& a)" << std::endl; }
void goo(A& a)  { std::cout << "goo(A& a)"  << std::endl; }

void foo(A&& a) {
    goo(a);             // 调用 goo(A& a)
    goo(std::move(a));  // 调用 goo(A&& a)
}

原因:a 的声明类型是 A&&,但它是一个具名变量,表达式 a 本身是左值。std::move 只做一次到右值的类型转换,让重载决议能选中 A&& 版本。

二、万能引用:可能可移动,用 std::forward

万能引用(T&&,且 T 由实参推导)绑定什么并不确定:传左值就绑左值,传右值才绑右值。所以转发时不能无条件地把它转成右值,否则左值实参也会被当作可移动对象掏空。

cpp 复制代码
class A {};

void goo(A&& t) { std::cout << "goo(A&& t)" << std::endl; }
void goo(A& t)  { std::cout << "goo(A& t)"  << std::endl; }

template <typename T>
void foo(T&& t) {
    goo(std::forward<T>(t));
}

void test() {
    A a;
    foo(a);     // 最终调用 goo(A& t)
    foo(A{});   // 最终调用 goo(A&& t)
}

std::forward<T> 做的是有条件的转换:

  • foo(a):T 推导为 A&,forward<A&> 返回左值 → goo(A&);
  • foo(A{}):T 推导为 A,forward<A> 返回右值 → goo(A&&)。

三、对照

形参 绑定的实参 转发方式 转换
A&& 只有右值 std::move 无条件
T&&(推导) 左值或右值 std::forward<T> 有条件

两者都只是类型转换,不搬运资源;真正干活的是移动构造和移动赋值。用反了都有代价:对万能引用无条件 move,会掏空调用者还要用的左值;对右值引用忘记 move,右值性丢失,轻则退化成拷贝,重则找不到可调用的重载。

相关推荐
码客-ygluu12 分钟前
X3 LUA 异步分布式微服务集群框架
c++·架构·lua
九英里路3 小时前
protobuf快速上手
网络·c++·中间件·json·谷歌·序列化·protobuf
纪念 2294 小时前
C++ 算法基础 (差分)
开发语言·c++·算法
ShineWinsu9 小时前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
落羽的落羽9 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
汉克老师14 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++
晴天的雨.99216 小时前
【C++】继承篇
java·开发语言·c++
青少儿编程课堂16 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛
another heaven16 小时前
【C/C++ 第一次跨越(上):用 C++11/14 停止制造新的旧代码】
c语言·c++·制造
qq_4069810316 小时前
c++ lamda(三)Lambda表达式
java·前端·c++