C++-详解C++11中的左值,左值引用,右值,右值引用

news2024/11/14 11:03:54

目录

一.C语言中对左值和右值的定义

        1.左值

        2.右值

二.左值引用和右值引用

        1.左值引用

        2.右值引用

        3.左值引用给右值取别名

       4.右值引用给左值取别名

三.移动构造和移动赋值

        1.移动赋值

        2.移动拷贝

​编辑​编辑

四.完美转发

        1.先看一道试题:

一.C语言中对左值和右值的定义

        C语言-数据对象,左值,右值-CSDN博客

        1.左值

                

                 定义:

                        左值是一个表示数据的表达式(比如变量名或解引用的指针)。

                        我们可以获取它的地址,一般可以对它进行赋值,左值可以出现在赋值符号的左边,右值不能出现在赋值符号的左边。

                        定义时const修饰后的左值,不能给他赋值,但是可以获取它的地址。

#include <stdio.h>

int main(void)
{
	const int a = 10;

	int b = a;

	return  0;
}

                对于int b = a;的解释:

                                 我们知道a是一个左值,但是同时右值本身又不可以是左值,那么这个a放到赋值运算符右边合理吗?

                                        其实这个是当我们将一个变量放到赋值运算符的右边时,会自动取出它的存储空间空间中的数据,而这个数据是右值。

        

        2.右值

                定义:右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引 用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址

                内置类型的右值   :纯右值。

                自定义类型的右值:将亡值。

二.左值引用和右值引用

        1.左值引用

                定义:左值引用就是左值的引用,给左值取别名。

                

        2.右值引用

                定义:右值引用就是右值的引用,给右值取别名。

                

                右值不可以被更改,但是右值引用可以被更改。 

        3.左值引用给右值取别名

                

                a + b这个表达式的值属性是保存在一个临时变量中的,临时变量具有常性 

       4.右值引用给左值取别名

                
                
                
                
                
                

三.移动构造和移动赋值

        1.移动赋值

string Func()
{
	string str("xxxxxxxxxx");

	return str;
}

int main(void)
{
	string ret;
	ret = Func();
	return  0;
}

        如果此时我们给的拷贝构造和赋值重载是这样的:

         

        此时就像我们的过程图中描述的一样,数据在从str到ret中的过程中发生了多次深拷贝,拷贝到没有什么,我们的计算机对于拷贝的处理是非常的快的,但是每次深拷贝时都会开辟新的空间,这个过程效率就很低了。

        解决办法:

        将赋值重载函数,写一个重载函数:

        此时程序的过程图就变为:

        

        移动赋值:

                内置类型的右值:将亡值。

                将亡值:马上就要被清理的自定义类型的对象。

                此时调用Func()产生的返回值(临时对象)就是一个将亡值。这个将亡值会被编译器处理成右值,所以此时ret=Func()会被调用

                        

                同时这个将亡值在这个表达式结束后就会被清理,但是这个临时对象中保存这我们想得到的数据,那么此时我们只需要将ret和这个临时对象中的数据进行互换就可以了。

                此时经过上面的操作,最后的赋值操作中我们并没有开辟新的空间,同时又近似的实现了深拷贝的操作。

                所以此时我们程序的效率提高了。

                

                上面的代码并不会发生移动赋值的情况!因为rett并不是自定义类型的右值,如果此时发生移动赋值,如果在此之后我们在想使用rett对象时,此时就会产生错误。

                但是:

                 

                这样程序是会发生移动赋值的,虽然move函数在调用完之后并不会改变rett对象本身是左值的属性,但是move函数的返回值可以让编译器认为此时rett对象是一个将亡值,可以发生移动赋值。

        2.移动拷贝

                在同一行代码中发生多次构造会被编译器优化为一次。

                虽然就像上图说的一样,经过编译器的优化,已经提高了我们程序的效率的,但是此时可不可以先移动赋值一样发生交换呢,做到一个新空间都不开辟呢?

                 移动构造:

                        此时只需要我们对拷贝构造函数进行改造:
                        

                                      

                        此时在编译器优化时会将str看成一个将亡值(右值),然后和ret进行交换。

                        所以当我们有了移动构造再来看移动赋值的代码:

                           

              此时1到2过程就不会在去调用深拷贝的拷贝构造了,直接调用移动拷贝就可以了。

                        两个疑惑:

                       

                          诚然我们在处理上面这样的情况时,确实应该在return中加move,但是如果没有编译器也会给我们进行优化的。

                                                        如果将返回值改为string&的,此时会产生两个问题

                                       a.因为str是局部对象,所以在出函数作用后会释放空间,所以此时会产生野指针的问题。

                                       b.string&后编译器不会在将str优化为右值,也就不可以发生移动构造了。

                

             左值引用的核心价值是减少拷贝,提高效率。

             右值引用的核心价值是进一步减少拷贝,弥补左值引用没有解决的场景,如:传值返回。 

         

四.完美转发

        1.先看一道试题:

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
template<typename T>
void PerfectForward(T&& t)
{
	Fun(t);
}
int main()
{
	PerfectForward(10);//右值
	int a;
	PerfectForward(a);// 左值
	PerfectForward(std::move(a)); // 右值
	const int b = 8;
	PerfectForward(b);// const 左值
	PerfectForward(std::move(b)); // const 右值
	return 0;
}

                 代码的运行结果是:

                 a.为什么此时函数模板中的明明是右值引用但是左值右值都可以接受?

                        

                        因为此时图中的引用是万能引用,因为此时函数模板的T是推导出来的。

                        

                b.为什么程序中即存在左值引用又存在右值引用但是却输出的结果都是左值引用呢?

                        因为在函数中Fun(t)即使是右值编译器也会将他看成左值。

                        解决方法:       

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
// std::forward<T>(t)在传参的过程中保持了t的原生类型属性。
template<typename T>
void PerfectForward(T&& t)
{
	Fun(std::forward<T>(t));
}
int main()
{
	PerfectForward(10);// 右值
	int a;
	PerfectForward(a);// 左值
	PerfectForward(std::move(a));// 右值
	const int b = 8;
	PerfectForward(b);// const 左值
	PerfectForward(std::move(b));// const 右值
	return 0;
}

         forward<T>保持此时数据的左右值属性。(完美转发)。

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

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

相关文章

C#实体类与XML互转以及List和DataTable转XML的使用

引言 在C#开发中&#xff0c;数据的存储和传输是非常常见的需求。使用XML作为数据格式有很多优点&#xff0c;例如可读性强、易于解析等。而实体类、List和DataTable是表示数据模型的常用方式。本文将介绍如何在C#中实现实体类、List和DataTable与XML之间的相互转换&#xff0c…

【100个Cocos实例】编码不规范,接手泪两行...

点击上方亿元程序员关注和★星标。 引言 规范编码&#xff0c;从文件头部注释规范做起。 头部注释规范是一种在代码文件开头添加注释信息的做法&#xff0c;通常用于描述文件的基本信息、作者、创建日期、修改历史等。 这有助于团队成员更好地理解和维护代码。 本文将介绍一…

基于Pix2Struct的文档信息提取【DocVQA】

文档信息提取涉及使用计算机算法从非结构化或半结构化文档&#xff08;例如报告、电子邮件和网页&#xff09;中提取结构化数据&#xff08;例如员工姓名、地址、职务、电话号码等&#xff09;。 提取的信息可用于各种目的&#xff0c;例如分析和分类。 DocVQA&#xff08;文档…

yolov5检测(前向)输入视频输出(不在图上画标签形式的原)图片的方法,及设置每隔几帧保存的方式(不每帧保存减少重复)

这些天我忽然有个需求&#xff0c;要更新迭代一个场景的检测模型&#xff0c;甲方爸爸提供的新数据集是监控视频形式的(因为拍视频确实更加的方便)&#xff0c;而我训练模型确实要标注好的图片形式。 根据这些条件的话&#xff0c;思路应该是要这样的&#xff1a;首先使用现有的…

EfficientViT:高分辨率密集预测的多尺度线性注意

EfficientViT: Multi-Scale Linear Attention for High-Resolution Dense Prediction 1、介绍2、方法2.1 多尺度线性注意模块2.1.1 启用全局接收域与ReLU线性注意2.1.2 解决ReLU线性注意力的局限性。 2.2 EfficientViT架构2.2.1 骨干2.2.2 头部 3、实验 贡献&#xff1a; 1、我…

【心得】XXE漏洞利用个人笔记

XML中关于DTD类型(内部(SYSTEM)的和外部(PUBLIC)的区别) xxe的利用 XML Entity 实体注入 当程序处理xml文件时&#xff0c;没有禁止对外部实体的处理&#xff0c;容易造成xxe漏洞 危害 主流是任意文件读取 XML 文件 一般表示带有结构的数据 祖父 3个叔父 8个堂弟堂妹 …

聚观早报 |魅族21搭载超声波指纹2.0;华为长安成立新公司

【聚观365】11月28日消息 魅族21搭载超声波指纹2.0 华为长安成立新公司 OPPO Reno11 Pro本周首销 淘宝天猫推出系列AI工具 长城汽车计划全面进入欧洲市场 魅族21搭载超声波指纹2.0 魅族官方此前已宣布&#xff0c;将于11月30日召开“2023魅族秋季无界生态发布会”&#x…

【JavaScript】封装自己的JavaScript公共工具函数,并上传到npm中 进行下载

js公共方法封装方式都有哪些 全局函数 function greet(name) {console.log("Hello, " name "!"); }greet("Alice"); // 调用全局函数对象字面量 var utils {add: function(a, b) {return a b;},subtract: function(a, b) {return a - b;}…

几何教学工具 Sketchpad几何画板 mac软件特色

Sketchpad几何画板 for Mac是一款适用于macOS系统的几何教学工具&#xff0c;用户可以在其画板上进行各种几何图形的绘制、演示&#xff0c;帮助教师了解学生的思路和对概念的掌握程度。此外&#xff0c;Sketchpad更深层次的功能则是可以用来进行几何交流、研究和讨论&#xff…

在Spring Boot中隔离@Async异步任务的线程池

在异步任务执行的时候&#xff0c;我们知道其背后都有一个线程池来执行任务&#xff0c;但是为了控制异步任务的并发不影响到应用的正常运作&#xff0c;我们需要对线程池做好相关的配置&#xff0c;以防资源过度使用。这个时候我们就考虑将线程池进行隔离了。 那么我们为啥要…

C#,数值计算——插值和外推,径向基函数插值(RBF_interp)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 径向基函数插值 /// Object for radial basis function interpolation using n points in dim /// dimensions.Call constructor once, then interp as many times as desir…

绝地求生:胜者组赛事强度再刷新,17即将晋级,NH闯地狱副本!

2023PGC胜者组赛终于在昨日打响&#xff0c;PCL战队17和Tianba各吃鸡&#xff0c;17更是以接近场均11分的高水准发挥确立了自己的优势。 胜者组再次让选手和观众体会到了不同的赛事强度&#xff0c;特别是艾伦格&#xff0c;未能吃到圈型的队伍最后只能轧点博取机会&#xff0c…

LangChain 13输出解析Output Parsers 自动修复解析器

LangChain系列文章 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数据库Faiss存储&#xff0c;读取YouTube的视频文本搜索I…

Sass 语法详细介绍

文章目录 前言SASS缩进语法SASS的语法差异多线选择器注释import Mixin指令已弃用的语法后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正…

机器态势感知中的注意力机制

输入矢量x是原始的输入数据&#xff0c;而q、k、v是通过对x进行线性变换得到的新的表示。q、k、v是通过对x分别乘以三个矩阵Wq、Wk、Wv得到的&#xff0c;其中Wq、Wk、Wv是通过学习得到的参数矩阵。这些参数矩阵通过模型训练过程中的反向传播算法来更新&#xff0c;以使得模型能…

振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(4)

注解目录 1、znFAT 的起源 1.1 源于论坛 &#xff08;那是一个论坛文化兴盛的年代。网友 DIY SDMP3 播放器激起了我的兴趣。&#xff09; 1.2 硬盘 MP3 推了我一把 &#xff08;“坤哥”的硬盘 MP3 播放器&#xff0c;让我深陷 FAT 文件系统不能自拔。&#xff09; 1.3 我…

新疆大学与优艾智合机器人成立联合创新实验室

11月22日至24日&#xff0c;第五届中国工业互联网大赛新疆赛站决赛在新疆维吾尔自治区昌吉回族自治州昌吉市举行。在大赛中崭露头角的优秀解决方案&#xff0c;将为绿色工厂、绿色园区、绿色供应链等建设提供新的动能&#xff0c;促进工业绿色发展。 作为大赛的成果延伸&#…

ESP32-Web-Server编程-建立第一个网页

ESP32-Web-Server编程-建立第一个网页 HTTP 简述 可能你每天都要刷几个短视频&#xff0c;打开几个网页来娱乐一番。当你打开一个网络上的视频或者图片时&#xff0c;其实际发生了下面的流程&#xff1a; 其中客户端就是你的浏览器啦&#xff0c;服务器就是远程一个存放视频或…

线性表的逻辑结构

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 只有靠自己的毅力忍耐&#xff0…

详解混合整数二次规划 (MIQP) 投资组合优化问题--附Matlab和Python实现

&#x1f517; 运行环境&#xff1a;Matlab、Python &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&am…