掌握std::move和std::forward

【移动语义和精准转发系列二】std::move和std::forward 在我们开始讲解std::move之前,先来介绍一个概念:引用折叠。这个概念仅用于 typedef 和 模板类型参数 中。 在模板世界中,T&& 称为Universal Reference,即通用引用。这与普通函数中形参的&&是不同的,希望不要弄混了。 对于模板函数template void func(T&& t),对于左值实参,T&& t 推导出的T为string&;对于右值实参,T&& t 阅读详情

在讲解std::move和std::forward之前,我们必须先了解C++中左值、右值的相关概念。

1、左值、右值

(1)左值:一般指的是在内存中有对应的存储单元的值,最常见的就是程序中创建的变量。
(2)右值:一般指的是没有对应存储单元的值(寄存器中的立即数,中间结果等),例如一个常量,或者表达式计算的临时变量。

判断某个表达式是左值还是右值的方法:

(1)可位于 = 左侧的表达式就是左值;反之,只能位于 = 右侧的表达式就是右值。

// 其中x是一个左值,字面值5是一个右值
int x = 5;

// 错误,5 不能为左值
5 = x;

说明:C++中的左值也可以当作右值使用。

// y 是一个左值
int y = 10;

// x、y 都是左值,但可以将 y 可以当做右值使用
x = y;

(2)有名称的、可以获取到存储地址的表达式即为左值;反之则是右值。

上述示例中变量 x、y 是变量名且通过 &x 和 &y 可以获得他们的存储地址,因此 x 和 y 都是左值;反之,字面量 5、10,它们既没有名称,也无法获取其存储地址,因此 5、10 都是右值。

2、左值引用、右值引用

(1)左值引用:C++中采用&对变量进行引用,我们平时熟悉的引用就是左值引用。

    int num = 10;
    int& b = num; //正确
    int& c = 10; //错误

    const int& c = 10; //正确

(2)右值引用:

因为右值本身也没有对应的存储单元,所以没法进行引用。右值引用实际上只是一个逻辑上的概念,最大的作用就是让一个左值达到类似右值的效果(下面程序举例),让变量之间的转移更符合“语义上的转移”,以减少转移之间多次拷贝的开销。右值引用符号是&&。

注意:
(1)右值引用不支持引用左值;
(2)非常量右值引用可以引用的值的类型只有非常量右值;
(3)常量右值可以引用常量右值、非常量右值。

int num1 = 10;
const int num2 = 100;

int&& a = num1;	//编译失败,非常量右值引用不支持引用非常量左值
int&& b = num2;	//编译失败,非常量右值引用不支持引用常量左值
int&& c = 10;	//编译成功,非常量右值引用支持引用非常量右值

const int&& d = num1;	//编译失败,常量右值引用不支持引用非常量左值
const int&& e = num2;	//编译失败,常量右值引用不支持引用常量左值
const int&& f = 100;	//编译成功,常量右值引用支持引用右值

3、move()函数

move()函数将左值强制转换成右值。但move()并没有移动能力!

int num = 10;
int&& a = std::move(num);  //编译成功
std::cout << a << std::endl;   //输出结果为10;
std::cout << num << std::endl; //输出结果为10;move只是把左值强制转换成右值,并没有移动能力。

a = 20;
std::cout << num << std::endl; //输出20

为了加深对move()的印象,我们再来看一个例子:

std::string str1 = "I love C++";
std::string str2 = std::move(str1);
std::cout << "str2:" << str2 << std::endl;
std::cout << "str1:" << str1 << std::endl;

执行结果:

我们看到执行move()函数后,str1里的内容没了,难道被移走了?我们前面说过move()没有移动能力,造成str1的内容为空的原因是string的“移动构造函数”。 我们再来看一个例子:

std::string str3 = "I love C";
std::string&& def = std::move(str3);
std::cout << "str3:" << str3 << std::endl;
std::cout << "def:" << def << std::endl;

执行结果:

4、forward()函数

std::forward的作用是完美转发,如果传递的是左值转发的就是左值引用,传递的是右值转发的就是右值引用。

std::move可以减少不必要的拷贝开销,可以提高程序的效率。但是std::forward的作用是转发,左值引用转发成左值引用,右值引用还是右值引用,它的意义到底是什么?

原来是在程序的执行过程中,对于引用的传递实际上会有额外的隐式的转化,一个右值引用参数经过函数的调用转发可能会转化成左值引用,但这就不是我们希望看到的结果。

举例:

#include <iostream>

template<typename T>
void print(T& t) {
    std::cout << "左值" << std::endl;
}

template<typename T>
void print(T&& t) {
    std::cout << "右值" << std::endl;
}

template<typename T>
void testForward(T&& v) {
    print(v);
    print(std::forward<T>(v));
    print(std::move(v));
}

int main(int argc, char* argv[])
{
    testForward(1); // 传入右值

    std::cout << "======================" << std::endl;

    int x = 1;
    testForward(x); // 传入左值
}

执行结果:

 

参考:

(1)[C++特性]对std::move和std::forward的理解

(2)【C++】左值和右值、左值引用(&)和右值引用(&&)

(3)抄袭李超老师的std::forward()

Effective Modern C++ 条款23:理解std::move和std::forward 前者是典型地为了移动操作,而后者只是传递(亦为转发)一个对象到另外一个函数,保留它原有的左值属性或右值属性。的吸引力在于它的便利性:减少了出错的可能性,增加了代码的清晰程度。是移动操作的候选者。接受一个对象的引用(准确的说,一个通用引用(universal reference),见。的,因为我们可以到处直接写转换代码,但是我希望我们能同意:这将相当的,嗯,让人恶心。返回的真的是右值引用,这很重要,因为函数返回的右值引用是右值。,你能确保的唯一一件事就是将它应用到一个对象上,你能够得到一个右值。 阅读详情

相关推荐

矿卡CMP 170HX的AI推理性能优化实战

GPU计算在现代AI推理中扮演着核心角色,其并行计算架构特别适合处理神经网络的大规模矩阵运算。通过CUDA指令集优化和计算管线重构,可以显著提升硬件利用率,这在边缘计算和带宽敏感型任务中尤为重要。以NVIDIA CMP 170HX矿卡为例,通过禁用FMA指令和框架适配优化,其FP32性能可提升15.9倍,在Qwen2.5-1.5B模型的4-bit量化推理中达到A100同架构78%的解码速度。这种优化技术不仅让淘汰矿卡重获新生,更为边缘AI部署提供了高性价比解决方案,特别适合7B以下量化模型部署和多路视频分析

weixin_30432579的博客 633

理解std::move和std::forward

首先通过了解它们(指std::move和std::forward)不做什么来认识std::move和std::forward是非常 有用的。std::move不move任何东西。std::forward也不转发任何东西。在运行时,他们什么 都不做。不产生可执行代码。 std::move和std::forward只是执行转换的函数(确切的说应该是函数模板)。std::move无条件的 将它的参数转换成一个右值,而std::forward当特定的条件满足时,才会执行它的转换。这就 是它们本来的样子.这样的解

猫哥 的沉淀、积累、总结。天天学习,好好向上...c/c++,嵌入式 linux,Android,HarmonyOS,AIOT) 3863

MAC M1用户必看:UTM虚拟机安装Win11全流程避坑指南(附驱动下载)

本文为MAC M1用户提供UTM虚拟机安装Win11的完整指南,涵盖镜像准备、驱动优化及性能调优等关键步骤。特别针对TPM 2.0验证、网络连接等常见问题提供解决方案,帮助用户高效运行Windows 11 ARM版。

weixin_29204205的博客 340

C++的std::move与std::forward

一、背景介绍 什么是左值和右值? 1、左值引用 C/C++语言中可以放在赋值符号左边的变量,即具有对应的可以由用户访问的存储单元,并且能够由用户去改变其值的量。或者说左值是代表一个内存地址值,并且通过这个内存地址,就可以对内存进行读并且写(主要是能写)操作。相对应的还有右值:当一个符号或者常量放在操作符右边的时候,计算机就读取他们的“右值”,也就是其代表的真实值。 简单来说就是,左值相当于地址值,右值相当于数据值。右值指的是引用了一个存储在某个内存地址里的数据。 左值右...

sinat_31608641的博客 2747

APM水下机器人实战:从零搭建高精度自主航行系统

本文详细介绍了如何基于开源APM飞控及其水下分支ArduSub,从零搭建高精度自主水下航行器。核心在于集成双天线RTK模块实现厘米级定位与精确航向,并配合MAVROS与ROS构建自主控制系统。文章涵盖了硬件选型、软件配置、自主逻辑开发及水池调试的全流程实战经验,为水下机器人爱好者与研究者提供了一套完整的自主航行系统解决方案。

app77的博客 512

Zemax非序列模式实战:手把手教你设计光纤耦合圆光斑整形系统(附Thorlabs透镜选型)

本文提供了一份基于Zemax非序列模式的光纤耦合圆光斑整形系统实战设计指南。文章详细讲解了从圆柱体光源建模、Thorlabs商业透镜库选型调用,到系统搭建、光线追迹与优化的完整流程,旨在帮助工程师高效完成从仿真到落地的光束整形系统设计。

weixin_28335283的博客 632

C++的std::move与std::forward原理大白话总结

阅读大型的C++开源项目代码,基本逃不过std::move和std::forward,例如webRTC。 所以搞懂其原理,很有必要。 网络上已有不少文章介绍(见@参考),但是比较分散,所以我把自认为的关键点,加上一些自己的想法,提取总结一下。 1. std::move 别看它的名字叫move,其实std::move并不能移动任何东西,它唯一的功能是将一个左值/右值强制转化为右值引用,继而可以通过右值引用使用该值,所以称为移动语义。 1.1 函数原型 函数定义原型: /** * @brief Conve

newchenxf的专栏 1万+

华为OD机试 双机位A卷 - 流量波峰 (C++ & Python & JAVA & JS & GO)

华为OD机试双机位A卷 流量波峰,提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解

qq_45776114的博客 1377

std::move与std::forward

std::move与std::forward

ELCstar的专栏 1087

Android16 RK3576修改亮度调节为线性调节

文章摘要: 本文分析了Android系统中亮度调节的非线性问题,并提供了线性化改造方案。首先通过追踪Settings和SystemUI代码,发现亮度调节使用了BrightnessUtils类中的非线性Gamma空间转换算法。然后重点修改了BrightnessUtils类,将原有的Hybrid Log Gamma(HLG)算法替换为简单的线性映射公式。最后在自定义工具窗口中实现了基于系统标准接口的亮度调节功能,通过SeekBar的0-100%百分比值线性映射到1-255的系统亮度值。改造后的亮度调节更加直观,

tzj1058756809的博客 76

带洞多边形如何分成凸多边形集合,对多边形进行凸分解?

摘要: 凸分解是计算几何中的经典问题,分为三角化和凸分解两种方法。三角化将带洞多边形转换为简单多边形并分割为三角形,常用算法包括耳剪法、单调多边形三角化等。凸分解则生成更少但更大的凸多边形,常用Hertel-Mehlhorn算法或基于凹点的递归切割。实际应用中建议使用CGAL、Poly2Tri等成熟库处理。三角化适合图形渲染,凸分解更适用于物理引擎和路径规划。关键步骤包括数据校验、选择合适的算法及后处理优化。

插件开发 355

C++11中std::move和std::forward到底干了啥

C++11中的右值引用的出现,在特定情况下减少了对象的拷贝,提升了C++程序的效率,伴随而来的 `std::move` 和 `std::forward` 也大量出现在程序代码中,但是这两个函数究竟干了啥呢?其实他们的本质都是转换函数,也就是完成左值和右值之间的转换,需要注意的是左值可以转换成右值,但是右值无法转换成左值...

AlbertS Home of Technology 6674

使用 Pfam 和 InterProScan 进行蛋白质家族和功能域的分析

本文介绍了使用Pfam和InterProScan进行蛋白质家族与功能域分析的方法。主要内容包括:1) Pfam数据库的本地化使用,通过hmmscan工具比对Pfam-A.hmm数据库,并提供了批量处理Python脚本;2) InterProScan的安装配置与命令行参数详解,支持多数据库整合分析;3) 补充介绍了基于curl的Uniprot在线查询方法。文章提供了从软件安装到实战分析的完整流程,适用于本地化、批量化蛋白质功能注释需求,特别是无网络环境或大规模数据分析场景,适合不同水平的生物信息学用户。

Protein Designer的博客 1918

浅谈std::move和std::forward原理

本文主要整理了C++11中std::move和std::forward的原理, 这对理解C++的移动拷贝有很重的意义。

爱拼才会赢 3975

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

std::move和std::forward

std::move是c++11引入的,用于将一个资源"移动"到另一个对象,而不是复制。但是通过std::move的源码可以发现,其底层实际并没有"转移"的动作,那是如何实现呢?通过源码可以发现,std::move的底层实际只是进行了类型强制转换,将一个变量强制转换成了一个右值。1.remove_reference_t:用于类型转换,用于移除_Ty的引用,如果_Ty是T&或者T&&,都会变成T类型2._Arg是函数参数,并且是一个右值引用,因此参数可以是左值也可以是右值。

weixin_47326789的博客 586

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C++理解std::move和转发(std::forward)

/在返回类型和类型转换中也要用到typename这段代码很短,但其中有些微妙之处。首先,move的函数参数T&&是一个指向模板类型参数的右值引用。通过引用折叠,此参数可以与任何类型的实参匹配。特别是,我们既可以传递给move一个左值,也可以传递给它一个右值,"),s2;"));// 正确:从一个右值移动数据// 正确:但在赋值之后,s1的值是不确定的//没有打印任何东西为了通过翻转函数传递一个引用,我们需要重写函数,使其参数能保持给定实参的“左造性”。

2301_80224556的博客 1622

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

条款23:理解std::move和std::forward

Effective Modern C++之条款23

weixin_43739503的博客 930

C++:std::move 和 std::forward

先看一个简单的示例,注意他们的输出结果。

彭世瑜的博客 1289

C++11 std::move和std::forward

https://www.jianshu.com/p/b90d1091a4ff 下文先从C++11引入的几个规则,如引用折叠、右值引用的特殊类型推断规则、static_cast的扩展功能说起,然后通过例子解析std::move和std::forward的推导解析过程,说明std::move和std::forward本质就是一个转换函数,std::move执行到右值的无条件转换,std::forwa...

$firecat利白的代码足迹$ 1057

std::move和std::forward 深度剖析

1 引入的规则 规则1(引用折叠规则):如果间接的创建一个引用的引用,则这些引用就会“折叠”。 一般情况下,引用折叠成一个普通的左值引用类型。 X& &、X& &&、X&& &都折叠成X& 一种特殊情况下,引用会折叠成右值引用,即右值引用的右值引用, T&& &&。 X&& &&折叠为X&& 规则2(右值引用的特殊类型推断规则):当将

qq_27727147的博客 769

std::move和std::forward的区别

std::move:“我要移动这个对象的资源”—— 强制转为右值,用于明确触发移动语义。:“按原样转发这个参数”—— 保持原始值类别,用于模板中实现完美转发。move是“无条件右值化”,forward是“有条件保持原值类别”。

u010632343的博客 533

c++中std::move和std::forward

std::move无条件转换到右值。就其本身而言,它没有move任何东西。 std::forward只有在它的参数绑定到一个右值上的时候,它才转换它的参数到一个右值。 std::move和std::forward在运行期都没有做任何事情。它们没有产生需要执行的代码,1个byte都没有。 std::move和std::forward只不过就是执行cast的两个函数(实际上是函数模板)。 std...

qq_35331967的博客 435

std::move 和 std::forward

特性std::move目的强制转为右值,触发移动语义保持参数原始值类别,完美转发转换条件无条件依赖模板参数T典型应用移动构造函数、避免拷贝泛型代码中的参数转发参数类型接受任意类型通常与万能引用T&&配合使用。

Black_Silencer的博客 548

C++ std::move 和 std::forward 实现

std::forward 仅仅对绑定到右值的引用实施向右值类型的强制类型转换,即仅当传入的实参被绑定到右值时候,std::forward才强制转化为右值。std::move 和 std::forward 都是仅仅执行强制类型转换的函数(底层为函数模板),2. std::forward的实现, 参考visual studio实现。3. remove_reference_t 实现如下。std::move 无条件的将实参强制转化为右值,1. std::move 的实现。

MyBigOrange的博客 450
上一篇: c++中的时间处理(3)与sleep相关的时间函数
下一篇: C++内存池(1)理论基础及简单实现
老蔡编程
博客等级 码龄23年 48粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值