理解C++中的右值引用

面试题:什么是右值引用?右值引用与左值引用的区别 上一篇博客剖析了引用的底层实现原理,文中所述的“引用”默认表示为左值引用。 一、左值与左值引用 什么是左值引用呢? 左值引用,就是绑定到左值的引用,通过&来获得左值引用。 那么,什么是左值呢? 左值,就是在内存有确定存储地址、有变量名,表达式结束依然存在的值。 左值可以分为两类:非常量左值和常量左值;同理,右值也可以分为两类:非常量右值和常量左值。 左值引用举例说明: int a=10; //非常量左值(有确定存储地址,也有变量名) const int a1=10; 阅读详情

右值引用,顾名思义,就是对一个右值进行引用,或者说给右值一个别名。右值引用的规则和左值一用一模一样,都是对一个值或者对象起个别名。

1. 右值引用和左值引用一样,在定义的同时必须立即赋值,如果不立即赋值,语法错误,看下面的例子

class A
{
    public:
    int m_val;
    A(int n):m_val(n) {    }
    A(A&& a)
    {
        m_val=a.m_val;
         cout<<"move constructor is called"<<endl;
    }
    A& operator=(const A&r)
    {
        if(this!=&r)
        {
            m_val=r.m_val;
            cout<<"move assignment operator is called"<<endl;
        }
    }
    ~A()
    {
        cout<<"Destructor is called"<<endl;
    }
};
int main(int argc, char const *argv[])
{
    A a(10);        //定一个对象(左值)
    A& lr=a;        //左值引用,同时赋值
    A&& rr=move(a);  //定义右值引用,同时赋值
    A&& rr2;        //定义右值引用,但是没有赋值
    rr2=move(a);    //非法
    return 0;
}

2. 右值引用的操作和左值引用一样,操作右值引用,就是操作源对象本身,因为右值引用就是源对象的一个别名。看下面的例子,操作左值引用、右值引用、源对象中的任何一个,其它两个都相应变化。

class A
{
    public:
    int m_val;
    A(int n):m_val(n) {    }
    A(A&& a)
    {
        m_val=a.m_val;
         cout<<"move constructor is called"<<endl;
    }
    A& operator=(const A&r)
    {
        if(this!=&r)
        {
            m_val=r.m_val;
            cout<<"move assignment operator is called"<<endl;
        }
    }
    ~A()
    {
        cout<<"Destructor is called"<<endl;
    }
};
int main(int argc, char const *argv[])
{
    A a(10);        //定一个对象(左值)
    A& lr=a;        //左值引用,同时赋值
    A&& rr=move(a);  //定义右值引用,同时赋值
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;
    cout<<"change value by original object"<<endl;
    a.m_val=20;
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;

    cout<<"change value  by left reference"<<endl;
    lr.m_val=30;
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;

    cout<<"change value  by right reference"<<endl;
    rr.m_val=40;
    cout<<"lr.m_val="<<lr.m_val<<" "<<"rr.m_val="<<rr.m_val<<" "<<"a.m_val="<<a.m_val<<endl;
    cout<<"left reference and right reference won't create any new object"<<endl;
    return 0;
}

输出结果如下:再次证明,引用就是起别名

3. 从上图可以看出,引用不会产生任何新的对象。

4. 右值引用和移动构造函数、移动赋值运算符没有任何关系。

5. 右值引用被正确赋值以后,还能被二次赋值,引用到一个新的对象上吗?不能。右值引用一旦被定义,随后的操作就对源对象的操作了。看下面这个例子:

class A
{
    public:
    int m_val;
    A(int n):m_val(n) {    }
    A(A&& a)
    {
        m_val=a.m_val;
         cout<<"move constructor is called"<<endl;
    }
    A& operator=(const A&r)
    {
        if(this!=&r)
        {
            m_val=r.m_val;
            cout<<"move assignment operator is called"<<endl;
        }
    }
    ~A()
    {
        cout<<"Destructor is called"<<endl;
    }
};
int main(int argc, char const *argv[])
{
    A a1(10);
    A a2(20);
    A&& rf=move(a1);

    rf=move(a2);        //不是对右值引用进行新的引用,而是等价为:a1=move(a2)
    cout<<"rf.m_val="<<rf.m_val<<"   "<<"a2.m_val= "<<a2.m_val<<endl;
    a2.m_val=30;
    cout<<"rf.m_val="<<rf.m_val<<"   "<<"a2.m_val= "<<a2.m_val<<endl;
    return 0;
}

rf=move(a2);不是二次引用,而是等价为a1=move(a2),因为rf就是a1,这里一个移动赋值运算符被调用了

牢牢记住,右值引用就是给右值(纯右值、将亡值)起个别名,延长右值的生命周期,没看到多大的使用价值。

另外,定义右值引用的时候,经常看到move函数,但是右值引用和move没有任何关系,move的作用是把一个左值强制转换为右值,具体参考这里:真正理解std::move-优快云博客

LIS3DHTR三轴加速度计Arduino驱动与嵌入式集成指南 加速度计是嵌入式系统中实现运动感知、姿态解算和振动分析的核心传感器。其工作原理基于MEMS微机械结构在惯性力作用下的电容变化,经片内ADC转换为数字信号;I²C接口因其硬件资源占用少、布线简洁,成为低功耗物联网节点的主流通信方式。技术价值体现在高分辨率(12位)、多量程(±2g~±16g)与低功耗(待机电流仅2µA)的平衡,支撑电池供电设备长期运行。典型应用场景包括可穿戴设备的姿态识别、工业预测性维护中的振动监测,以及智能硬件的敲击/跌落检测。本文围绕LIS3DHTR芯片及其Grove模块,详解Arduin 阅读详情

相关推荐

【Web实战】微信小程序逆向

2E 70 6E 67”为带存放路径的文件名称,“00 00 11 7C”对应文件在小程序包中的具体偏移位置,“00 01 01 F7“对应文件在小程序包中的数据长度。但这并不是最初的原项目文件结构,原因是微信服务器会将小程序源码中所有的“js”文件压入“app-service.js”文件中,将所有的“json”文件压入“app-config.json”中,将所有的“wxml”文件压入“page-frame.html”文件中,“wxss”则在处理之后以“html”文件的形式存留在对应页面目录之下。

若有战,召必回 1941

C++中的通俗理解左值,右值,左值引用,右值引用

move的意思是把左值的名字移出掉(其实还是可以用a去调用),所以会变成右值,因此一个左值一旦用了move, 最好保证它在move后不要再被调用,毕竟move的思想就是把名字除去了,毕竟都被除名了,也就是想表达以后我不会再叫你a了。会编译报错,为什么?因为a是一个左值,a *2 这里是利用了a的右值属性,所以a *2 会生成一个没有名字的右值,你去给一个没有名字的内存块取别名是不行的,因为他都没有名字,何来别名一说?因为a是一个左值,而&&是给右值起第一个名字,你都有名字了还来用&&凑热闹,所以编译报错。

feng__shuai的博客 727

从农田到城市:如何利用NDVI和缨帽变换提升遥感图像分类精度?

本文深入探讨了如何利用NDVI(归一化差值植被指数)和缨帽变换(Tasseled Cap Transformation)两大关键技术,有效提升从农田到城市等复杂场景的遥感图像分类精度。文章通过剖析地物光谱特征,对比了原始波段与衍生特征的优劣,并提供了在ENVI、ArcGIS及Python环境中的具体操作指南与实战策略,旨在帮助从业者构建更鲁棒的特征工程流程,从而解决地物混淆、边界模糊等常见分类难题。

redis7keeper的博客 865

c++中的右值引用的简单理解

以下的内容是我看了网上的博文后自己的总结,如果时间充裕的话,建议直接看原文。 简介:   c++中的右值引用十分不好理解,但是当你大概知道右值引用解决了c++中的什么问题后,会感觉右值引用还是很有用的。平时我们在c++中使用的引用为了和c++11引入的右值引用区分,一般把它称之为左值引用。左值引用很好理解,就是多个变量名绑定到了同一块内存上,操作这几个不同的变量名相当于操作同一块内存...

aong5154的博客 686

ENVI5.6+SARscape实战:基于哨兵一号的PS与SBAS时序InSAR地表形变监测全流程解析

本文详细解析了使用ENVI5.6和SARscape软件基于哨兵一号数据进行PS与SBAS时序InSAR地表形变监测的全流程。从数据获取、预处理到PS-InSAR和SBAS-InSAR处理,提供了实用技巧和优化建议,帮助用户高效完成地表形变监测任务。

weixin_29245767的博客 1151

C#调用opencv的dll

opencv算法和界面配合,刚入职的时候尝试过,利用的MFC,调试起来很痛苦。 后来基本都没怎么用界面,DOS的黑窗口,opencv自带的显示界面及滑动条凑合着调试用。 最近有点时间,刚好双十一在一个视觉群里看到了一个讲C#调用opencv的dll的课程,鉴于群主也是那门课的讲师,在平时解答群员的问题的时候很细心,能力也很强,因此有了这篇文章。 根据相机不同动态调用相机默认的属性...

Learning by doing 2972

如何理解C++中的左值引用与右值引用

如何理解C++中的左值引用与右值引用

weixin_42809924的博客 290

【LAMMPS学习】五、LAMMPS命令(1) LAMMPS 输入脚本

本部分描述了 LAMMPS 输入脚本的格式以及其中的命令如何用于定义 LAMMPS 模拟。主要包括以下内容。

荷塘阅色 2644

【C++11特性篇】一文助小白轻松理解 C++中的【左值&左值引用】【右值&右值引用】

本文介绍了左值&左值引用,右值&右值引用,配有简洁明了的代码与思维导图帮助大家理解。同时还介绍了左值引用右值,右值引用左值的规则

YYDsis的博客 1227

Open3D KD-tree的使用【2025最新版】

Open3d使用FLANN构建KDTree以便进行快速最近邻检索。博客长期更新,本文最近一次更新时间为:2025年1月1日,代码已同步更新至Open3D 0.18.0版本。

点云侠的博客 40万+

笔试题-2023-芯原-数字前端设计or验证【纯净题目版】

笔试题-2023-芯原-数字前端设计or验证【纯净题目版】

w0shishabi的博客 5685

深入理解 C++ 标准中的右值引用

在 C++ 中,值可以分为左值(lvalue)和右值(rvalue)。简单来说,左值是有名称并且在程序执行期间可被访问的位置,而右值则是临时的、不可直接获取存储位置的值。例如:代码语言:cppAI代码解释int x = 10;// x 是一个左值// (x + 5) 是一个右值传统的 C++ 引用(即左值引用)只能绑定到左值上。这种设计的局限性在某些情况下会导致不必要的拷贝操作和性能损失。因此,C++11 引入了右值引用,允许程序员直接操作右值,从而提供更高效的编程模型。

2509_93923299的博客 719

java零基础从入门到精通(全)

目录前言1. 入门知识1.1 java体系1.2 JDK/JRE/JVM区别1.3 编译与运行理解1.4 类体函数细节2. 标识符 前言 java优势 健壮性(JVM(C++语言写的一个虚拟的计算机)、GC(垃圾回收机制)) 多线程并发 可移植性/跨平台 1. 入门知识 1.1 java体系 JavaSE:标准版 JavaEE:企业版 JavaME:微型版 1.2 JDK/JRE/JVM区别 JVM是不能独立安装的。 JRE和JDK都是可以独立安装的 层层嵌套,jvm包括jdk,jdk包括jre

码农研究僧的博客 6万+

C++中的右值引用与移动语义的理解

右值引用:C++中定义的对右值的引用// 这里a的地址就是这个语句中5的地址int b = 5;// 这里b的地址和这个语句中5这个临时变量**移动语义:**对于含有指针类型作为成员数据的类,使用移动而不是深拷贝进行初始化或者赋值。具体体现就是类的移动构造函数和移动赋值函数;也就是传入一个右值引用(就相当于给这个临时变量),然后让本对象的指针的值直接等于该临时对象指针的值,然后将临时对象的指针再置为空。这样避免了深拷贝那样的内存开销。

qq_55841287的博客 403

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

深入理解 C++ 中的引用:左值引用与右值引用

本文介绍了C++的左值引用与右值引用

TIME_LEAF的博客 433

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++中的右值引用与通用引用:区分与理解(Effective Modern C++ 条款24)

本文详细解析C++中的右值引用与通用引用的区别。右值引用(T&&)只能绑定右值,用于实现移动语义;通用引用(T&&)则通过类型推导确定,可绑定左值或右值,常用于模板函数或auto&&声明。区分关键在于类型推导是否存在及初始化值类型。正确区分二者对实现移动语义、完美转发及提高代码可读性至关重要。文章通过具体示例说明两者的使用场景,帮助开发者更高效地利用C++11特性。

软件科学-郝学胜 1211

NTscan扫描工具

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

volatile关键字在C++中的作用是什么?如何理解C++中的右值引用和移动语义?

如果这个变量没有被声明为volatile,编译器可能会优化代码,假设该变量的值在一段时间内保持不变,从而导致读取到的是错误的、已经过时的值。总的来说,volatile关键字在C++中用于告诉编译器变量的值可能会在不可预知的情况下被改变,从而确保每次访问该变量时都会直接从其内存地址读取,而不是使用可能已经缓存的值。即使一个变量是volatile的,多个操作(如自增)仍然可能不是原子的,也就是说,在多线程环境中,这些操作可能会被其他线程中断,导致数据不一致。由于v是一个局部对象,在函数返回时它将被销毁。

Aaron的博客 930

《深入理解 C++中的右值引用:开启高效编程新篇章》

C++中的右值引用是一个强大而又富有特色的特性,它为程序员提供了更高效的资源管理方式和更灵活的编程手段。在未来的 C++编程中,右值引用将继续发挥重要的作用,为程序员带来更多的便利和创新。右值引用可以延长临时对象的生命周期。与传统的左值引用不同,右值引用可以绑定到右值上,即那些没有名字、只能在表达式中出现一次的对象。在 C++的编程世界中,右值引用是一个强大而又富有特色的特性,它为程序员提供了更高效的资源管理方式和更灵活的编程手段。在函数参数传递中,使用右值引用可以避免不必要的拷贝,提高函数的性能。

xy520521的博客 725
上一篇: C++ 中的常量表达式和编译器优化
下一篇: 真正理解std::move
SONG_CA
博客等级 码龄24年 74粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值