左值/右值/左值引用/右值引用/万能引用/移动语义/完美转发,你真的懂了吗?

【C++】右值引用详解(移动构造、移动赋值、万能引用和完美转发、关键字default和delete) 右值引用总结 阅读详情

C++整了这么一套花活,最终的目的就是:减少拷贝,节省内存,提高运行效率。

在看本文之前,如果你能清晰区分下面前两个函数的异同,并知道为啥第三个函数调用非法,你就可以继续阅读本文了。

void F1(int a){a++;}

void F2(int& a){a++;}

F2(100);  //compile error

一、左值和右值

左值就是一个数据的表达式,这个表达式指向一块内存,并且允许我们对这块内存取地址,可以这么认为,可以取地址的对象或变量就是左值,左值通常可以被赋值,但被 const 修饰后的左值,不能给它赋值,但是仍然可以取它的地址。

右值不能取地址,也不能被赋值,即:右值不能出现在赋值表达式的左边。

根据上述定义,下面的a、p、b都是左值

int a = 3;

int* p = &a;

const int b = 2;

问:*p是左值还是右值。*p,又叫解引用,就是解释引用,或者说直接去寻找指针所指的地址里面的内容,于是这个表达式指向一块内存,内存的地址就是p的值,因此解引用也是个左值。

下面这些都是右值

double x = 1.3, y = 3.8;

 10; // 字面常量

x + y; // 表达式返回值

fmin(x, y);

问下述函数是左值还是右值?

int a=10;

int& Incerease(int &b)

{

b++;

return b;

}

我们可以写出如下代码,因此int& Incerease(int &b)是个左值。

Incerease(a)=50;

二、左值引用和右值引用

记住一句话:无论左值引用还是右值引用,都是给对象取别名 。

左值引用:

左值引用就是对左值的引用,给左值取别名,左值引用使用一个&来表示。主要作用是避免对象拷贝。

  1. 左值引用只能引用左值,不能直接引用右值。 
  2. 但是const左值引用既可以引用左值,也可以引用右值 

int& ra = a;

int*& rp = p;

int& r = *p;

const int& rb = b;

const double& d1=10.7

右值引用

右值引用就是对右值的引用,给右值取别名,具体表示就是在变量类型名称后加&&。

int&& n1=10;

double&& d1=x+y;

double&& d2=fmin(x,y);

右值引用引用右值,会使右值被存储到特定的位置。
也就是说,右值引用变量其实是左值,可以对它取地址和赋值(const右值引用变量可以取地址但不可以赋值,因为 const 在起作用)。
当然,取地址是指取变量空间的地址(右值是不能取地址的)

  1. 右值引用只能引用右值,不能直接引用左值。 
  2. 但是右值引用可以引用被move的左值。 

无论是左值引用变量还是右值引用变量,都是左值。

三、使用左值引用和右值引用的意义
1. 不使用左值引用

看下图,如果在函数Func1中不使用引用的话,当str被传入Func1的时候,在Func内部首先产生一次拷贝构造,外部的str拷贝给函数内部的str,数字1所示。

在str被处理以后,该str将被传回到函数外部,于是在数字2处也产生一次拷贝构造,内部的str传出到外部的一个临时变量。

该临时变量也被调用一次拷贝构造,给外部的str1赋值,数字3,于是我们可以看到,一共产生了三次调用拷贝构造函数(不考虑编译器优化的情况)

2. 使用左值引用

如果传参使用左值引用,那么只有两次拷贝构造函数的调用

如果函数返回一个左值引用,那么就只有一次拷贝构造函数的调用

2. 使用右值引用

在讲右值引用之前,先来讲一下一个类中都有哪些函数。在C++ 11之前,编译器通常会为一个类准备4个函数,如果你不为这个类准备的话:

默认无参构造函数

拷贝构造函数

赋值运算符重载

析构函数。

在c++11之后,有增加了两个函数:移动构造函数和移动赋值运算符。这两个函数都比相应的拷贝构造函数和赋值运算符重载要高效的多。

看下面这个例子:

在Func1被调用的时候,1处有一个右值引用,右值引用只是给右值(str)起一个名字(str2),在新名字上的操作等同于对原始右值的操作。参见4处的两个对象的地址完全一致。

2处有一个右值返回,函数返回一个右值引用的对象(str2, 也就是str),是个右值。这个对象要赋值给一个新的对象str1,于是右值移动构造函数被调用。在3处有一个移动构造函数。当然新的对象str1除了把str的内容借过来,已经与str是两个完全不同的两个对象了,于是我们看到str内容为空了。

move 本意为 "移动",但该函数并不能移动任何数据,它的功能很简单,就是将某个左值强制转化为右值,以便可以通过右值引用使用该值。看下面的例子,r是右值引用,就是x的别名,我们可以通过操作r来改变x。

我们知道,非 const 右值引用只能操作右值,程序执行结果中产生的临时对象(例如函数返回值、lambda 表达式等)既无名称也无法获取其存储地址,所以属于右值。当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数

四、万能引用

在此之前我们需要知道什么是万能引用:

确定类型的 && 表示右值引用(比如:int&& ,string&&),
但函数模板中的 && 不表示右值引用,而是万能引用,模板类型必须通过推断才能确定,其接收左值后会被推导为左值引用,接收右值后会被推导为右值引用。

注意区分右值引用和万能引用:下面的函数的 T&& 并不是万能引用,因为 T 的类型在模板实例化时已经确定。

template<typename T>
class A
{
    void func(T&& t);  // 模板实例化时T的类型已经确定,调用函数时T是一个确定类型,所以这里是右值引用
};

让我们通过下面的程序来认识万能引用:

template<typename T>
void F1(T& t1)
{
    cout<<t1<<endl;
}

int main()
{
    int n=1;
    F1(n);  // good
    F1(1);  //error
    return 0;   
}

嫩F1(1)导致编译错误。为了修正这个错误,我们重载另一个函数:

template<typename T>
void F1(T& t1)
{
    cout<<t1<<endl;
}
template<typename T>
void F1(T&& t1)
{
    cout<<t1<<endl;
}
int main()
{
    int n=1;
    F1(n);  // good
    F1(1);  //error
    return 0;   
}

能否把两个函数合二为一,可以:

使用T&&类型的形参既能绑定右值,又能绑定左值。

但是注意了:只有发生类型推导的时候,T&&才表示万能引用;否则,表示右值引用

五、完美转发

完美转发是指在函数模板中,完全依照模板的参数类型,将参数传递给当前函数模板中的另外一个函数。

因此,为了实现完美转发,除了使用万能引用之外,我们还要用到std::forward(C++11),它在传参的过程中保留对象的原生类型属性。

这样右值引用在传递过程中就能够保持右值的属性

继续利用前面的一个例子,我们把函数的返回类型不使用右值引用,这次返回一个临时变量,这个临时变量会被拷贝构造函数赋值给str1. str2是一个右值引用,但str2本身是一个左值。因此return str2 就会通过拷贝构造str2,返回一个临时变量。这也就是我们说的右值引用失去了右值的属性,成为了一个左值,如何能保持str2的右值属性呢?这就引入了完美转发。

下面看如何使用完美转发来保持str2的右值属性,

总结:

右值引用和左值引用类似,都是为一个量(对象)起了个别名,操作右值引用和左值引用等价于操作被引用量本身。

DOTween回调函数的隐藏技巧:优化你的Unity动画流程 本文深入探讨了DOTween回调函数在Unity动画开发中的高级应用技巧,帮助开发者优化动画流程。通过分析回调机制、链式应用模式和大规模动画系统管理,提升性能与可维护性,特别适合需要高效处理复杂动画场景的Unity开发者。 阅读详情

相关推荐

华南理工大学电子与信息学院23年预推免复试面试经验贴

华南理工大学电子与信息学院23年预推免复试面试经验贴

Scut_Ty的博客 3295

C++ 学习系列 1 -- 左值、右值与万能引用

在 T 是模板参数时,T&& 的作用主要是保持值类别进行转发,它有个名字就叫“转发引用”(forwarding reference)。因为既可以是左值引用,也可以是右值引用,它也曾经被叫做“万能引用”(universal reference)。可以延长右值的生命周期,右值的生命周期可以与右值引用变量相同。简单的说,左值可以放在等号的左边,右值可以放在等号的右边。中的引用部分,只获取其中的类型部分。是左值还是右值,最后只获取它的类型部分。左值可以取地址,右值不能取地址。为左值引用的左值变量,通过。

qq_33775774的博客 461

Python爬取腾讯视频m3u8加密流实战(附完整代码)

本文提供了一份详细的Python实战教程,指导如何通过抓包分析、模拟请求头与载荷,破解腾讯视频的m3u8加密流防盗链机制,并附上完整代码实现视频片段的下载与合并。教程涵盖从侦察到代码实现的完整流程,并包含参数动态化、多线程下载等高级技巧与避坑指南,旨在帮助开发者掌握流媒体下载的核心技术。

weixin_29090089的博客 1589

【C++】右值引用与移动语义详解:如何利用万能引用实现完美转发

大家好,我是店小二。本篇文章将深入讲解C++11的新增特性,重点围绕右值引用与移动语义展开,并详细讨论如何利用万能引用实现完美转发。如果在阅读过程中有疑问或不同的见解,欢迎随时私信我进行进一步交流

专注于 C/C++ 后端开发,涵盖基础语法、Linux系统与网络、MySQL数据库、常见算法及项目经验。 4219

【MediaPipe实战】从零构建实时人脸关键点检测与表情分析系统

本文详细介绍了如何使用MediaPipe框架从零构建实时人脸关键点检测与表情分析系统。通过Python代码实现,系统能够精准检测468个3D人脸关键点,并实时分析用户表情,适用于智能交互应用。文章包含环境配置、核心实现、可视化技巧及性能优化等实战内容,帮助开发者快速掌握深度学习在计算机视觉中的应用。

weixin_30836759的博客 72

linux离线安装nginx

linux离线安装nginx

zhang_130914036的博客 9346

C++左值与右值の深思——万能引用与完美转发

带你一命通关C++左右值原理 十分钟手撕语法内涵

qq_61500888的博客 3856

RK3568移植AP6256

本文主要是记录RK3568移植正基的AP6256的WIFIBT模块,感兴趣的朋友可以一起学习!!!提示:以下是本篇文章正文内容,下面案例可供参考。

qq_24093081的博客 3715

C++11: 右值引用,移动语义,万能引用,完美转发,新的默认成员函数

C++11: 右值引用,移动语义,万能引用,完美转发,新的默认成员函数

Wzs040810的博客 1796

光谱数据预处理综合

除了化学信息,光谱还包含其他不相关或不需要的信息,如电噪声,基质背景,杂散光,散射效应等。在用化学计量学方法建立校准模型时,利用预处理方法消除光谱数据中的无关信息和噪声是非常必要的。

qq_44204759的博客 5189

YOLO11改进|注意力机制篇|引入ELA注意力机制

YOLO11添加ELA注意力机制

A1983Z的博客 3647

【C++杂货铺】一文总结C++11新特性:右值引用 | 移动语义 | 完美转发

本篇文章介绍了C++11中新引入的右值引用,对左值、左值引用、右值、右值引用进行了详细的区分。介绍了左值引用的缺陷,以及为什么要引入右值引用,分别列举了左值引用和右值引用各自的使用场景,最后介绍了什么是完美转发,以及完美转发的实际应用场景。

春人.的博客 8730

【Flink】FlinkSQL如何触发执行计算

Table (通过 StatementSet.addInsert() 输出给某个 Sink)和 INSERT 语句 (通过调用 StatementSet.addInsertSql())会先被缓存到 StatementSet 中,StatementSet.execute() 方法被调用时,所有的 sink 会被优化成一张有向无环图。该方法是用来将一个表的内容插入到目标表中,一旦该方法被调用, TABLE API 程序立即被翻译。该方法是用来执行一个 SQL 语句,一旦该方法被调用, SQL 语句立即被翻译。

一杯咖啡半杯糖的博客 1005

【C++11】:右值引用&移动语义&完美转发

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。

2301_77900444的博客 2329

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C++11新特性 -- 右值引用与移动语义超详解

右值引用与移动语义。 本篇文章会涵盖: 左值与右值的区别,怎么去区分左值与右值。右值引用的概念,为什么要增加右值引用,右值引用的作用,解决了什么问题, 右值引用与左值引用的比较,右值引用的使用场景,右值引用的注意事项,完美转发的使用,C++11后容器新增的两个默认函数等等

2301_77509762的博客 1723

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C++11 ——— 右值引用和移动语义

传统的C++语法中就有引用的语法,而C++11中新增了右值引用的语法特性,为了进行区分,于是将C++11之前的引用就叫做左值引用。但是无论左值引用还是右值引用,本质都是给对象取别名,左值引用就是对左值的引用,给左值取别名,通过“&”来声明,右值引用就是对右值的引用,给右值取别名,通过“&&”来声明。

2021dragon的博客 6319

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【C++】C++11——左右值|右值引用|移动语义|完美转发

【C++】C++11——左右值|右值引用|移动语义|完美转发

weixin_60478154的博客 3009

右值引用和移动语义

介绍了左值和右值的概念,右值引用,完美转发等知识

qq_74319491的博客 1471

右值引用与移动语义

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以我们称之前学习的引用为左值引用。但无论左值引用还是右值引用,其实都是给对象取别名。

GG_Bruse的博客 8298

[C++11#45](二) 右值引用 | 移动语义 | 万能引用 | 完美转发forward | 初识lambda

本文首先介绍了C++中的左值和右值概念,并详细对比了左值引用与右值引用的区别。通过探讨右值引用实现的底层优化,特别是在容器和字符串处理中的应用,展示了其在提高性能方面的重要作用。接着,文章阐述了完美转发技术,包括万能引用的概念及其如何实现数据类型的精确传递。此外,补充讨论了移动赋值操作和右值引用引用左值的特殊情况。最后,文章转向lambda表达式,简要介绍了其引入背景和基本语法,帮助读者理解这一强大的语言特性。

No Game No Life 1754

【C++】C++11 ~ 右值引用和移动语义

但行好事,莫问前程

qq_42996461的博客 1972

C++ 左右值、左右引用、万能引用、引用折叠、完美转发详解

首先我们需要知道什么叫转发,这里的转发指的时,函数调用过程中参数的传递过程。完美转发则是指参数转发过程中保持其参数类型(指左右值),最外层函数如果传入的是一个右值,那么其希望在转发过程中该参数始终绑定到一个右值引用上(即继续作为右值),如果传入的是一个左值,那么其希望始终绑定到一个左值引用上(即继续作为左值)。

qq_45523675的博客 2905

左值引用和右值引用

一、左值和右值 glvalue 可寻址的表达式,即可使用&操作符的表达式 prvalue 只读表达式,即不可使用&操作符的表达式 xvalue 延长了生命周期的表达式,即右值引用 lvalue 等号左边的值 rvalue 等号右边的值 二、左值引用和右值引用 引用是一种类型 左值引用:普通的引用 右值引用:可以延长临时对象的生命周期 三、移动构造 四、模版 ...

gb173652770的专栏 1万+

【右值引用、移动语义、万能引用与完美转发】

右值引用可以解决传入的函数参数是将亡值的问题右值引用可能是左值也可能是右值,若这个右值引用被命名了,它就是左值移动语义可以减少无谓的内存拷贝,要想实现移动语义,需要实现移动构造函数和移动赋值运算符若想对一个左值进行移动构造,可用std::move将一个左值转换成一个右值使用***T&&类型的形参既能绑定右值,又能绑定左值。只有发生类型推导的时候,才表示万能引用;引用折叠规则:所有的右值引用叠加到右值引用上仍然是一个右值引用,其他引用折叠都为左值引用。当。

qq_43317082的博客 1060

左值引用与右值引用(移动语义)

但在深拷贝的类中引入C++11的移动构造后,这里仍然需要再调用一次赋值运算符重载函数进行深拷贝,因此深拷贝的类不仅需要实现移动构造,还需要实现移动赋值。例如下面这种情形。

weixin_67401681的博客 1163

42.C++11-右值引用与移动语义/完美转发

C++中右值引用的概念,移动语义与完美转发的实现,左右值饮用都联系与区别。

yzc的博客 1592
上一篇: Git, 你必须要知道的那些事(1)
下一篇: 到底什么是type traits
SONG_CA
博客等级 码龄24年 74粉丝 20原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值