c++之说_14|左值引用与右值引用

提起左右值引用我就头疼

左值:

1、在内存中开辟了空间的便叫左值

2、左值不一定可以赋值  如字符串常量

3、左值可以取地址

右值:

1、在内存中没有开辟空间的

2、右值无法取地址

如:

立即数(1,2,3)

函数返回值 直接返回非类型引用

Lvalue getT() { return Lvalue(); };
int get() { return c;  };

返回的这个int值或Lvalue类型对象就是一个右值 因为没有开辟空间

3、将亡值

什么叫将亡值  我的理解是一种标志 告诉说这个对象我要销毁

Lvalue&& getR();  函数返回值是右值引用 返回的这个对象 就叫将亡对象  即将销毁Lvalue c;
static_cast<Lvalue&&>(c);  转换返回的操作数也叫将亡值

我的理解就是告诉我们 这个值是要销毁的  推荐使用一个新对象去存储

  什么叫左值引用? 其实就是 这个对象所代表的内存空间的另一个名字  在编译器内部

  本质上是指针实现的

   对左值引用取地址  所取的是引用对象的地址值

Lvalue d;//左值const Lvalue& b2 = d;//绑定左值
Lvalue& b3 = d;//绑定左值&b2 == &d;
&b3 == &d;

而右值引用 则引用的是右值

Rvalue r;//左值
Rvalue&& r1 = Rvalue();//绑定右值//r1 是左值  有名的右值引用  为 左值
const Rvalue&& r2 = static_cast<Rvalue&&>(r1);//绑定右值(实际上是左值转换到右值)成将亡值Rvalue&& r3 = static_cast<Rvalue&&>(r);

记住有名字的右值引用  是左值  所以可以取地址

std::cout << "r:" << &r << endl;
std::cout << "r1:" << &r1 << endl;
std::cout << "r2:" << &r2 << endl;
std::cout << "r3:" << &r3 << endl;&r == &r3;
&r1 == &r2;

由于是引用  当然可以改变所引用的对象

struct Rvalue
{};
struct Lvalue : public Rvalue
{int c;Lvalue() = default;Lvalue(int Inc) :c(Inc) {};Lvalue getT() { return Lvalue(); };Lvalue&& getR() { auto c = new Lvalue(100);  return static_cast<Lvalue&&>(*c);};int get() { return c;  };
};
std::cout << "" << endl;
Lvalue op(50);
std::cout << "op.c:" << op.c << endl;
Lvalue& Lop = op;
Lop.c = 100;
std::cout << "左值引用修改"<< endl;
std::cout << "op.c:" << op.c << endl;
Lvalue& Rop = op;
Lop.c = 800;
std::cout << "右值引用修改" << endl;
std::cout << "op.c:" << op.c << endl;

这么一看左右值引用都是一样的感觉

他们主要体现在函数上

struct Lvalue : public Rvalue
{int c;int* p;Lvalue() = default;Lvalue(int Inc) :c(Inc), p(new int()) {};Lvalue& operator=(Lvalue& lc) { c = lc.c;p = new int;*p = * lc.p;return *this; };Lvalue& operator=(const Lvalue& lc) {c = lc.c;p = new int;*p = *lc.p;return *this; };Lvalue& operator=(Lvalue&& lc) {c = lc.c;p = lc.p;lc.p = nullptr;return *this;};Lvalue& operator=(const Lvalue&& lc) {	Lvalue&& Rc = const_cast<Lvalue&&> (lc);c = Rc.c;p = Rc.p;Rc.p = nullptr;return *this; };Lvalue getT() { return Lvalue(); };Lvalue&& getR() { auto c = new Lvalue(100);  return static_cast<Lvalue&&>(*c);};int get() { return c;  };
};

注意那几个 operator= 重载赋值运算符的函数

这其实就是所谓的 深拷贝  浅拷贝

//深拷贝
Lvalue& operator=(Lvalue& lc) 
{ c = lc.c;p = new int;    //重新开辟了堆空间 *p = * lc.p;    //将 lc.p 中的int值 存入新开的堆空间中return *this; 
};//浅拷贝
Lvalue& operator=(Lvalue&& lc) 
{c = lc.c;p = lc.p;        
//没有开辟新的堆空间  直接拿到 将亡值 lc 的 p所存储的内存地址  达到复用的目的
// 这也是他们所说的窃取资源lc.p = nullptr;return *this;
};
Lvalue& operator=(Lvalue& lc) 
{ std::cout << "Lvalue& operator=(Lvalue& lc)" << endl;c = lc.c;delete p;p = new int;*p = * lc.p;return *this; 
};
Lvalue& operator=(const Lvalue& lc) 
{std::cout << "Lvalue& operator=(const Lvalue& lc)" << endl;c = lc.c;delete p;p = new int;*p = *lc.p;return *this; 
};
Lvalue& operator=(Lvalue&& lc) 
{std::cout << "Lvalue& operator=(Lvalue&& lc) " << endl;c = lc.c;delete p;p = lc.p;lc.p = nullptr;return *this;
};
Lvalue& operator=(const Lvalue&& lc) 
{	std::cout << "Lvalue& operator=(const Lvalue&& lc) " << endl;Lvalue&& Rc = const_cast<Lvalue&&> (lc);c = Rc.c;delete p;p = Rc.p;Rc.p = nullptr;return *this; 
};

调用处

Lvalue t1(100);
*t1.p = 80;
Lvalue t2(200);
*t2.p = 800;
std::cout << "" << endl;
std::cout << "初始化时" << endl;
std::cout << "t1.c:" << t1.c << endl;
std::cout << "t1.p:" << t1.p << endl;
std::cout << "*t1.p:" << *t1.p << endl;
std::cout << "" << endl;
std::cout << "t2.c:" << t2.c << endl;
std::cout << "t12.p:" << t2.p << endl;
std::cout << "*t2.p:" << *t2.p << endl;std::cout << "" << endl;
std::cout << "t1 = t2" << endl;t1 = t2;//Lvalue& operator=(Lvalue& lc) ;std::cout << "t1.c:" << t1.c << endl;
std::cout << "t1.p:" << t1.p << endl;
std::cout << "*t1.p:" << *t1.p << endl;
std::cout << "" << endl;
std::cout << "t2.c:" << t2.c << endl;
std::cout << "t12.p:" << t2.p << endl;
std::cout << "*t2.p:" << *t2.p << endl;std::cout << "" << endl;
std::cout << "t1 = static_cast<Lvalue&&>(t2)" << endl;t1 = static_cast<Lvalue&&>(t2); 
//Lvalue& operator=(Lvalue&& lc)  如果没有  就考虑 Lvalue& operator=(const Lvalue&& lc)  
如果还没有 就调用Lvalue& operator=(const Lvalue& lc) std::cout << "t1.c:" << t1.c << endl;
std::cout << "t1.p:" << t1.p << endl;
std::cout << "*t1.p:" << *t1.p << endl;
std::cout << "" << endl;
std::cout << "t2.c:" << t2.c << endl;
std::cout << "t12.p:" << t2.p << endl;
//std::cout << "*t2.p:" << *t2.p << endl; //访问空指针是错误的

我们注释掉

/* Lvalue& operator=(Lvalue&& lc) 
{std::cout << "Lvalue& operator=(Lvalue&& lc) " << endl;c = lc.c;delete p;p = lc.p;lc.p = nullptr;return *this;
}; */Lvalue& operator=(const Lvalue&& lc) 
{	std::cout << "Lvalue& operator=(const Lvalue&& lc) " << endl;Lvalue&& Rc = const_cast<Lvalue&&> (lc);c = Rc.c;delete p;p = Rc.p;Rc.p = nullptr;return *this; 
};

看调用 Lvalue& operator=(const Lvalue&& lc) 

我们继续注释

/* Lvalue& operator=(Lvalue&& lc) 
{std::cout << "Lvalue& operator=(Lvalue&& lc) " << endl;c = lc.c;delete p;p = lc.p;lc.p = nullptr;return *this;
}; *//*
Lvalue& operator=(const Lvalue&& lc) 
{	std::cout << "Lvalue& operator=(const Lvalue&& lc) " << endl;Lvalue&& Rc = const_cast<Lvalue&&> (lc);c = Rc.c;delete p;p = Rc.p;Rc.p = nullptr;return *this; 
};
*/

看调用与结果

这就是右值引用存在的价值

告诉大家这个对象需要销毁  你怎么处理看你的了  

如果只用左值引用 无法很好的区分  因为cosnt lvalue&&  即可左值也可右值

你不知道传进来的这个对象是 const 修饰的对象  还是  要表示的销毁对象

我们也看到了引用是可以直接修改对象的  所以也是会有点问题  有些人不按照规则来

这样的函数 是有隐患的  我的本意是  这个返回值是即将销毁的值  然而外部可修改

Lvalue&& getR() { auto c = new Lvalue(100);  return static_cast<Lvalue&&>(*c);
};

折叠引用  使用类型别名  using  typedef  即可达到折叠引用的目的

using ob = Lvalue&;
typedef Lvalue& ob1;
using ou = Lvalue&&;
typedef Lvalue&& ou1;Lvalue k;
ob& o = k;//左值引用
ob && o1= k;//左值引用
ou& o2 = k;//左值引用
ou&& o3 = (Lvalue&&)k;//右值引用

折叠引用只有一个规则:

右值引用的右值引用 才是右值引用  其余都为左值引用

&& &&  右值引用

& && 左值引用

&& & 左值引用

& & 左值引用

而我们所知晓的 std::forward 完美转发  返回值就是  &&

用了点折叠引用

好了  到最后了 

我们说一下

空类 和 继承 一个空类 内存大小是什么样的

Lvalue d;//左值
Rvalue r;//左值
std::cout<<	sizeof(d)<<endl;//4   继承一个空类  空类所占的1字节被优化掉
std::cout << sizeof(r) << endl;//1

  写完了

对了知乎大佬的参考  左右值引用的要点  

(3 条消息) c++为什么要搞个引用岀来,特别是右值引用,感觉破坏了语法的简洁和条理,拷贝一个指针不是很好吗? - 知乎 (zhihu.com)

最后参考代码


struct Rvalue
{};
struct Lvalue : public Rvalue
{int c;int* p;Lvalue() = default;Lvalue(int Inc) :c(Inc), p(new int()) {};Lvalue& operator=(Lvalue& lc) { std::cout << "Lvalue& operator=(Lvalue& lc)" << endl;c = lc.c;delete p;p = new int;*p = * lc.p;return *this; };Lvalue& operator=(const Lvalue& lc) {std::cout << "Lvalue& operator=(const Lvalue& lc)" << endl;c = lc.c;delete p;p = new int;*p = *lc.p;return *this; };/*Lvalue& operator=(Lvalue&& lc) {std::cout << "Lvalue& operator=(Lvalue&& lc) " << endl;c = lc.c;delete p;p = lc.p;lc.p = nullptr;return *this;};*//*Lvalue& operator=(const Lvalue&& lc) {	std::cout << "Lvalue& operator=(const Lvalue&& lc) " << endl;Lvalue&& Rc = const_cast<Lvalue&&> (lc);c = Rc.c;delete p;p = Rc.p;Rc.p = nullptr;return *this; };*/Lvalue getT() { return Lvalue(); };Lvalue&& getR() { auto c = new Lvalue(100);  return static_cast<Lvalue&&>(*c);};int get() { return c;  };
};int main(int line,   const char* arg[])
{Lvalue d;//左值Rvalue r;//左值std::cout<<	sizeof(d)<<endl;//4   继承一个空类  空类所占的1字节被优化掉std::cout << sizeof(r) << endl;//1//const 修饰的左值引用 既可以绑定左值又可以绑定右值     Lvalue() 右值  无名的const Lvalue& b = Lvalue();//绑定右值const Lvalue& b2 = d;//绑定左值Lvalue& b3 = d;//绑定左值Rvalue&& r1 = Rvalue();//绑定右值//r1 是左值  有名的右值引用  为 左值const Rvalue&& r2 = static_cast<Rvalue&&>(r1);//绑定右值(实际上是左值转换到右值)Rvalue&& r3 = static_cast<Rvalue&&>(r);//std::move(r);std::cout << "左值"<< endl;std::cout << "d:"<< & d << endl;std::cout << "b2:"<< &b2 << endl;std::cout << "b:" << &b << endl;std::cout << "b3:" << &b3 << endl;std::cout << "右值"<< endl;std::cout << "r:" << &r << endl;std::cout << "r1:" << &r1 << endl;std::cout << "r2:" << &r2 << endl;std::cout << "r3:" << &r3 << endl;//td::cout << "纯右值" << &Rvalue() << endl; //error//&d.getT();decltype(auto) v = d.getR();v.c = 50;std::cout << "v:" << &v << endl;auto str = "dadad";std::cout << "字符串:" << &"dadad" << endl;std::cout << "str:" << &str << endl;std::cout << "" << endl;Lvalue op(50);std::cout << "op.c:" << op.c << endl;Lvalue& Lop = op;Lop.c = 100;std::cout << "左值引用修改"<< endl;std::cout << "op.c:" << op.c << endl;Lvalue& Rop = op;Lop.c = 800;std::cout << "右值引用修改" << endl;std::cout << "op.c:" << op.c << endl;int&& i = 10;i = 80;Lvalue t1(100);*t1.p = 80;Lvalue t2(200);*t2.p = 800;std::cout << "" << endl;std::cout << "初始化时" << endl;std::cout << "t1.c:" << t1.c << endl;std::cout << "t1.p:" << t1.p << endl;std::cout << "*t1.p:" << *t1.p << endl;std::cout << "" << endl;std::cout << "t2.c:" << t2.c << endl;std::cout << "t12.p:" << t2.p << endl;std::cout << "*t2.p:" << *t2.p << endl;std::cout << "" << endl;std::cout << "t1 = t2" << endl;t1 = t2;//Lvalue& operator=(Lvalue& lc) ;std::cout << "t1.c:" << t1.c << endl;std::cout << "t1.p:" << t1.p << endl;std::cout << "*t1.p:" << *t1.p << endl;std::cout << "" << endl;std::cout << "t2.c:" << t2.c << endl;std::cout << "t12.p:" << t2.p << endl;std::cout << "*t2.p:" << *t2.p << endl;std::cout << "" << endl;std::cout << "t1 = static_cast<Lvalue&&>(t2)" << endl;t1 = static_cast<Lvalue&&>(t2); //Lvalue& operator=(Lvalue&& lc)  如果没有  就考虑 Lvalue& operator=(const Lvalue&& lc)  如果还没有 就调用Lvalue& operator=(const Lvalue& lc) std::cout << "t1.c:" << t1.c << endl;std::cout << "t1.p:" << t1.p << endl;std::cout << "*t1.p:" << *t1.p << endl;std::cout << "" << endl;std::cout << "t2.c:" << t2.c << endl;std::cout << "t12.p:" << t2.p << endl;//std::cout << "*t2.p:" << *t2.p << endl; //访问空指针是错误的using ob = Lvalue&;typedef Lvalue& ob1;using ou = Lvalue&&;typedef Lvalue&& ou1;Lvalue k;ob& o = k;//左值引用ob && o1= k;//左值引用ou& o2 = k;//左值引用ou&& o3 = (Lvalue&&)k;//右值引用std::forward<Lvalue&&>(k);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2779239.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

移动端web开发布局

目录 flex布局&#xff1a; flex布局父项常见属性&#xff1a; flex布局子项常见属性&#xff1a; REM适配布局&#xff1a; 响应式布局&#xff1a; flex布局&#xff1a; 需要先给父类盒子设置display&#xff1a;flex flex是flexiblebox的缩写&#xff0c;意为"弹…

面试经典150题——三数之和

​"The road to success and the road to failure are almost exactly the same." - Colin R. Davis 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力方法 因为三个数相加为0&#xff0c;那么说明其中两个加数的和与另一个加数为相反数则满足题意。所以可以得到…

猫头虎分享已解决Bug || IndexError: index 3 is out of bounds for axis 0 with size 3

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

解决挂梯子 无法正常上网 的问题

方法&#xff1a; 打开 控制面板 &#x1f449; 网络和Internet &#x1f449; Internet选项 &#x1f449; 连接 &#x1f449; 局域网设置 &#x1f449; 代理服务器 &#x1f449; 取消选项 有问题可参考下图

案例:三台主机实现 级联复制

介绍&#xff1a;级联复制架构 级联复制架构 是一种特殊的主从结构&#xff0c;之前聊到的几种主从结构都只有两层&#xff0c;但级联复制架构中会有三层&#xff0c;关系如下&#xff1a; 也就是在级联复制架构中&#xff0c;存在两层从库&#xff0c;这实际上属于一主多从架…

Failed to construct ‘RTCIceCandidate‘ sdpMid and sdpMLineIndex are both null

最近在搞webrtc&#xff0c;在编写函数处理远端传递来的candidate时报错了&#xff0c;具体信息如下。国内关于webrtc的资料很少&#xff0c;所以去国外社区转了一圈&#xff0c;回来记录一下报错的解决方案 其实这个bug也好解决&#xff0c;根据报错信息可以判断是RTCIceCand…

C语言第二十二弹---指针(六)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1. 回调函数是什么&#xff1f; 2、qsort使用举例 2.1、使用qsort函数排序整型数据 2.2 使用qsort排序结构体数据 3、qsort函数的模拟实现 总结 1. 回…

龙年,大吉

&#xff08;1&#xff09; 没有成功的企业&#xff0c;只有时代的企业。这就是人们老说的&#xff1a;天道酬勤。虽然这句话被人说滥了&#xff0c;虽然这句话被人说到反感了&#xff0c;但事实就是这样。 得道者多助。 &#xff08;2&#xff09; 人有三大运、三小运。 三大运…

Python基础语法(内置Python, pycharm配置方式)

一.工具安装与配置 1.Python解释器的安装 官网网址:https://www.python.org/ 选择downloads即可(Windows用户点击Windows, 苹果用户点击macOS) 找到最新版本, 并选择 Download Windows installer (64-bit) 下载完成后可在得到一个安装包进行安装(安装时间较长) 安装完成后…

【JMX】JAVA监控的基石

目录 1.概述 2.MBean 2.1.Standard MBean 2.2.Dynamic MBean 2.3.Model Bean 2.4.Dynamic MBean和Model Bean的区别 2.5.MXBean 2.6.Open Bean 3.控制台 1.概述 什么是JMX&#xff0c;首先来看一段对话&#xff1a; Java Management Extensions&#xff08;JMX&#…

【Wio Terminal教程】使用LCD屏幕(4)

使用LCD屏幕&#xff08;4&#xff09; 一、TFT LCD的API例子1、实用图形2、数据显示3、字体4、作为背景显示 二、如何在Wio Terminal上使用LVGL图形库1、安装Seeed_Arduino_LvGL2、示例1. Bench Mark2. Stress Test3.资源 一、TFT LCD的API例子 本节为TFT LCD库的例子提供了一…

ERROR: Could not build wheels for roslz4

Python bugs 最近在安装python的rosbag包时出现了诸多问题&#xff0c;特别记录下。 python版本&#xff1a;3.11 系统版本&#xff1a;Windows10 x86_64 使用conda虚拟环境进行包管理。 运行命令 pip3 install roslz4 --extra-index-url https://rospypi.github.io/simple…

【数据结构与算法】【小白也能学的数据结构与算法】递归 分治 迭代 动态规划 无从下手?一文通!!!

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

|Python新手小白低级教程之项目篇——turtle库|第一章:turtle库基础(1)

项目篇—文章目录 一、预告二、turtle基础1.导入2.画图代码&#xff08;1&#xff09;turtle.forward(长度)练习1.1 画线段 &#xff08;2&#xff09;turtle.left()和turtle.right()操作符练习2.1 画出边长为100正方形练习2.2 画出边长为100的三角形 &#xff08;3&#xff09…

腾讯云4核8G12M轻量应用服务器性能够用吗?支持多少人?

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…

Web前端-移动web开发_rem布局

文章目录 移动web开发之rem布局1.0 rem基础1.1 rem单位(重点)1.2 em单位(了解)1.3 媒体查询什么是媒体查询媒体查询语法规范 1.4 less 基础维护css弊端Less 介绍Less安装Less 使用之变量使用node编译less的指令Less 编译 vocode Less 插件Less 嵌套Less 运算Less中的Mixin混入L…

车载测试Vector工具——常见问题汇总

车载测试Vector工具——常见问题汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何 消耗你的人和事,多看一眼都是你的…

C++重新入门-循环

目录 1.循环类型 while循环&#xff1a; for循环 基于范围的for循环(C11) do...while 循环 2.循环控制语句 3.无限循环 有的时候&#xff0c;可能需要多次执行同一块代码。一般情况下&#xff0c;语句是顺序执行的&#xff1a;函数中的第一个语句先执行&#xff0c;接着…

《零基础实践深度学习》基于线性回归实现波士顿房价预测任务1.3.3

1.3.3 基于线性回归实现波士顿房价预测任务 深度学习不仅实现了模型的端到端学习&#xff0c;还推动了人工智能进入工业大生产阶段&#xff0c;产生了标准化、自动化和模块化的通用框架。不同场景的深度学习模型具备一定的通用性&#xff0c;五个步骤即可完成模型的构建和训练&…

vs2019 - signtool签名和验签的手工操作

文章目录 vs2019 - signtool签名和验签的手工操作概述笔记导入根证书时间戳服务器的选择code sign - 签名文件在代码签名(code sign)前后的区别签名后, 查看属性, 是正常的.用signtool命令行进行验签移除签名END vs2019 - signtool签名和验签的手工操作 概述 signtool是进行c…