当前位置: 首页 > news >正文

理解C++中的右值引用

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

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;        //定义右值引用,但是没有赋值rrw=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的作用是把一个左值强制转换为右值

http://www.lryc.cn/news/527133.html

相关文章:

  • 02-机器学习-核心概念
  • 1.26 实现文件拷贝的功能
  • ES6+新特性,var、let 和 const 的区别
  • HarmonyOS简介:HarmonyOS核心技术理念
  • 嵌入式C语言:结构体对齐
  • 【Rust自学】15.5. Rc<T>:引用计数智能指针与共享所有权
  • 谈谈RTMP|RTSP播放器视频view垂直|水平反转和旋转设计
  • decison tree 决策树
  • GO语言 链表(单向链表
  • Java:初识Java
  • Spring WebSocket 与 STOMP 协议结合实现私聊私信功能
  • 从0到1:C++ 开启游戏开发奇幻之旅(一)
  • 基于Flask的哔哩哔哩综合指数UP榜单数据分析系统的设计与实现
  • 在php中怎么打开OpenSSL
  • oracle 分区表介绍
  • wxwidgets直接获取系统图标,效果类似QFileIconProvider
  • Arduino大师练成手册 -- 控制 PN532 NFC 模块
  • 解决日志中 `NOT NULL constraint failed` 异常的完整指南
  • C动态库的生成与在Python和QT中的调用方法
  • UE求职Demo开发日志#7 强化属性完善
  • Day35:字符串的大小写转换
  • 喜报丨迪捷软件入选2025年浙江省“重点省专”
  • 深度剖析 PyTorch框架:从基础概念到高级应用的深度学习之旅!
  • 基于C++的DPU医疗领域编程初探
  • Linux 执行 fdisk -l 出现 GPT PMBR 大小不符 解决方法
  • 图漾相机搭配VisionPro使用简易教程
  • 第一届“启航杯”网络安全挑战赛WP
  • 大模型训练策略与架构优化实践指南
  • 新电脑安装系统找不到硬盘原因和解决方法来了
  • 【Linux】21.基础IO(3)