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,右值性丢失,轻则退化成拷贝,重则找不到可调用的重载。

相关推荐
程序猿编码1 小时前
YOLOv5/v7/YOLOX 全支持:基于 TensorRT 的工业视觉推理底座详解
c++·yolo·机器学习·推理·模型推理
kyle~1 小时前
C++ 原子操作、内存模型与无锁并发编程
linux·开发语言·c++·操作系统
another heaven2 小时前
【C/C++ C++ 面向对象架构的五大特点与能力场景:封装、继承、多态、抽象与 RAII(含实战案例)】
c语言·c++·架构
努力努力再努力wz2 小时前
【C++ 高阶系列】C++ 高性能网络编程:当 Reactor 遇见协程:从 epoll 回调到异步 MySQL,彻底打通任务挂起与恢复
网络·c++·mysql
霍霍的袁3 小时前
【C++11】左值右值引用与移动语义详细笔记(左值右值、右值引用、移动构造、移动赋值、引用折叠、万能转发)
c++·笔记·学习·visual studio
布莱克6053 小时前
C++ 中 unordered_set 与 unordered_map 有什么不同?一篇讲透
开发语言·c++·哈希
鶴哥只手遮天3 小时前
AFSIM 2.9.0 深度解析:架构、原理与工程实践-第 1 章 项目全景与代码地图
c++
充值内卷4 小时前
C++单文件迷宫游戏:TauriCPP 开发全记录
开发语言·c++·游戏
Antruly4 小时前
C++ Web 开发选型漫谈:从 Drogon 到 libuvcpp + uvp,八个项目的定位、兼容性与务实排名
开发语言·前端·c++