第6章 右值引用

6.1 左值和右值
 

区分左值与右值:

看能不能取地址 & 若能取地址则为左值  不能取地址为右值

int x = 1;
x++;//这个是右值
++x;//左值
++x实现 
int tmp = x;
x = x+1;
return tmp; 返回临时的

主要字符串也是左值 它可以取地址

6.2 左值引用

当我们需要将一个对象作为参数传递给子函数的时候,往往会使用左值引用,因为这样可以免去创建临时对象的操作。非常量左值的引用对象很单纯,它们必须是一个左值。对于这一点,常量左值引用的特性显得更加有趣,它除了能引用左值,还能够引用右值

int &a = 10;//报错
const int& a = 5;//常量引用
class X {
public:X() {}X(const X&) {}X& operator = (const X&) { return *this; }//这里是用在 x3 = make_X    函数得到是右值
};
X make_x()
{return X();//这里返回的是右值  需要用常量引用来接收 就是const X&
}
int main()
{X x1;X x2(x1);X x3(make_x());x3 = make_x();
}

 6.3 右值引用

常量左值引用可以绑定右值是一条非常棒的特性,但是它也存在一个很大的缺点——常量性。一旦使用了常量左值引用,就表示我们无法在函数内修改该对象的内容 引出右值引用

右值引用是一种引用右值且只能引用右值的方法
 

int&& t = 10;

右值引用的特点之一是可以延长右值的生命周期

# include <iostream>
class X {
public:X() { std::cout << "X ctor" << std::endl; }X(const X& x) { std::cout << "X copy ctor" << std::endl; }~X() { std::cout << "X dtor" << std::endl; }void show() { std::cout << "show X" << std::endl; }
};
X make_x()
{X x1;cout <<"1111  "<< & x1 << endl;return x1;
}
int main()
{X&& x2 = make_x();//这里不使用右值引用应该会发生三次构造 make_X中 x1一次return 一次 给x2一次//使用右值引用少了最后一次 给最后的临时变量的生命周期加长了
cout << "1111  " << &x2 << endl;x2.show();
}

6.4 右值的性能优化空间

#include <iostream>
class BigMemoryPool {
public:static const int PoolSize = 4096;BigMemoryPool() : pool_(new char[PoolSize]) {cout << "1111" << endl;}~BigMemoryPool(){if (pool_ != nullptr) {delete[] pool_;}}BigMemoryPool(const BigMemoryPool& other) : pool_(newchar[PoolSize]){std::cout << "copy big memory pool." << std::endl;memcpy(pool_, other.pool_, PoolSize);}
private:char* pool_;
};
BigMemoryPool get_pool(const BigMemoryPool& pool)
{return pool;
}
BigMemoryPool make_pool()
{BigMemoryPool pool;return get_pool(pool);
}
int main()
{BigMemoryPool my_pool = make_pool();
}

以上代码同样GCC需要加上编译参数-fno-elideconstructors

用VS的好像不能这样

这里会调用三次拷贝构造  get一个 make一个 最后 main函数返回值一个

还有很大的优化空间

6.5 移动语义

class BigMemoryPool {
public:static const int PoolSize = 4096;BigMemoryPool() : pool_(new char[PoolSize]) {}~BigMemoryPool(){if (pool_ != nullptr) {delete[] pool_;}}BigMemoryPool(BigMemoryPool&& other){std::cout << "move big memory pool." << std::endl;pool_ = other.pool_;other.pool_ = nullptr;}BigMemoryPool(const BigMemoryPool& other) : pool_(newchar[PoolSize]){std::cout << "copy big memory pool." << std::endl;memcpy(pool_, other.pool_, PoolSize);}
private:char* pool_;
};
BigMemoryPool get_pool(const BigMemoryPool& pool)
{return pool;
}
BigMemoryPool make_pool()
{BigMemoryPool pool;return get_pool(pool);
}
int main()
{BigMemoryPool my_pool = make_pool();
}

加入移动语句 这样后面两次的拷贝就变成了移动 

6.6 值类别

对于将亡值(xvalue),读者实际上只需要知道它是泛左值和右值交集即可
这里咕噜咕噜一大堆    等后边用到这些再回来看

6.7 将左值转换为右值

int a = 10;
int&& x = a ;//error 我们知道右值引用不能绑定左值 
int&& x = static_cast<int&&>(a); //这样子就行 显式的将左值转为将亡值
它的最大作用是让左值使用移动语义BigMemoryPool my_pool1;
BigMemoryPool my_pool2 = my_pool1;
BigMemoryPool my_pool3 = static_cast<BigMemoryPool &&>(my_pool1);
//my_pool1是左值 static_cast将它变为将亡值 可以使用移动语句 但是 后续不能对my_pool1操作了

无论一个函数的实参是左值还是右值,其形参都是一个左值,即使这个形参看上去是一个右值引用

void move_pool(BigMemoryPool &&pool)
{std::cout << "call move_pool" << std::endl;BigMemoryPool my_pool(pool);//这里是左值调用拷贝构造
}
int main()
{move_pool(make_pool());
}

要想用移动构造

void move_pool(BigMemoryPool &&pool)
{std::cout << "call move_pool" << std::endl;BigMemoryPool my_pool( static_cast<BigMemoryPool &&>pool);//这里是右值调用移动构造
}
int main()
{move_pool(make_pool());
}

将左值变为右值 还有move函数 内部就是用static_cast 只是它是模板函数 不需要直接定义类型 方便

6.8 万能引用和引用折叠

万能引用长的和右值引用一样 都是&&  若是有类型的推导就是万能引用 若是没有类型推导就是右值引用 

int&& a = 10;//右值引用
auto && x = 10//万能引用 

在模板当中&&含有类型推导都是万能引用 既可以用左值也可以用右值

使用万能引用右引用折叠 就是一堆的&&&这个

所有右值引用折叠到右值引用上仍然是一个右值引用。(A&& && 变成 A&&)
2.所有的其他引用类型之间的折叠都将变成左值引用。 (A& & 变成 A&; A& && 变成 A&; A&& & 变成 A&)

只要有左值引用参与进来,最后推导的结果就是一个左值引用。只有实际类型是一个非引用类型或者右值引用类型时,最后推导出来的才是一个右值引用。
万能引用的形式必须是T&&或者auto&&,也就是说它们必须在初始化的时候被直接推导出来
 

#include <vector>
template<class T>
void foo(std::vector<T>&& t) {}
int main()
{std::vector<int> v{ 1,2,3 };foo(v); // 编译错误
}

6.9 完美转发
 

与万能引用结合 : 万能引用用途

用于模板当中 用于传递参数 给调用函数 它真正的值类别 

为什么呢 

当我们在模板函数中传递参数时,通常会用泛型 T 来接收传入的参数。但是,如果我们传递的是右值而没有使用完美转发,右值的状态会被“降级”成左值,这意味着移动语义失效,编译器会认为这是一个左值并调用拷贝构造函数,而不是移动构造函数。

#include <iostream>
#include <utility>
#include <string>// 一个简单的类,用于模拟资源
class MyResource {
public:std::string name;MyResource(const std::string& n) : name(n) {std::cout << "Constructing " << name << std::endl;}MyResource(MyResource&& other) noexcept : name(std::move(other.name)) {std::cout << "Move constructing " << name << std::endl;}MyResource(const MyResource& other) : name(other.name) {std::cout << "Copy constructing " << name << std::endl;}
};// 这个函数接受任意类型的参数,并将它完美转发给另一个函数
template<typename T>
void passThrough(T&& arg) {std::cout << "passThrough called" << std::endl;process(std::forward<T>(arg));  // 完美转发
}// 用来处理传入的参数
void process(const MyResource& res) {std::cout << "Process by const lvalue reference: " << res.name << std::endl;
}void process(MyResource&& res) {std::cout << "Process by rvalue reference: " << res.name << std::endl;
}int main() {MyResource res1("Resource1");          // 创建一个对象passThrough(res1);                     // 传入左值,应该调用 lvalue 版本的 processpassThrough(MyResource("Resource2"));  // 传入右值,应该调用 rvalue 版本的 processpassThrough(std::move(res1));          // 显式地将 res1 转换为右值
}

6.10 针对局部变量和右值引用的隐式移动操作

c++20的用法略
 

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

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

相关文章

基于微信小程序校园订餐的设计与开发+ssm(lw+演示+源码+运行)

摘 要 人民生活水平的提高就会造成生活节奏越来越快&#xff0c;很多人吃饭都采用点外卖的方式。现在点外卖的平台已有很多&#xff0c;大多都需要安装它们的APP才可以使用&#xff0c;并且没有针对校园。如果一味的使用外卖平台不仅会造成商家成本的增加&#xff0c;还不利于…

基于微信小程序的智慧物业管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

C++容器list底层迭代器的实现逻辑~list相关函数模拟实现

目录 1.两个基本的结构体搭建 2.实现push_back函数 3.关于list现状的分析&#xff08;对于我们如何实现这个迭代器很重要&#xff09; 3.1和string,vector的比较 3.2对于list的分析 3.3总结 4.迭代器类的封装 5.list容器里面其他函数的实现 6.个人总结 7.代码附录 1.两…

easylogger移植

1.源码 GitHub - armink/EasyLogger: An ultra-lightweight(ROM<1.6K, RAM<0.3k), high-performance C/C log library. | 一款超轻量级(ROM<1.6K, RAM<0.3k)、高性能的 C/C 日志库 2.介绍 easylogger就是用来打印日志的,我们可以将日志输出到sscom, led屏幕, 或者…

多模态交互才是人机交互的未来

交互方式 在探讨文字交流、语音交流和界面交流的效率时&#xff0c;我们可以看到每种方式都有其独特的优势和局限性。文字交流便于记录和回溯&#xff0c;语音交流则在表达情绪和非语言信息方面更为高效&#xff0c;而界面交流则依赖于图形用户界面&#xff08;GUI&#xff09…

[大语言模型-论文精读] 以《黑神话:悟空》为研究案例探讨VLMs能否玩动作角色扮演游戏?

1. 论文简介 论文《Can VLMs Play Action Role-Playing Games? Take Black Myth Wukong as a Study Case》是阿里巴巴集团的Peng Chen、Pi Bu、Jun Song和Yuan Gao&#xff0c;在2024.09.19提交到arXiv上的研究论文。 论文: https://arxiv.org/abs/2409.12889代码和数据: h…

Mixamo动画使用技巧

1、登录Mixiamo网站 2、下载人物模型 3、找到FBX文件 选中人形骨骼 3、下载动画 4、拖拽FBX 5、注意事项 生成的FBX文件中会包含一个骨骼一个动画 如果人物有骨骼&#xff0c;则不需要&#xff0c;没有需要对应此包中的骨骼&#xff0c;骨骼不可以通用&#xff0c;动画通用 …

某集群管理系统存在任意文件读取漏洞

你为什么要拼命努力&#xff1f;父母的白发&#xff0c;想去的地方很远&#xff0c;想要的东西很贵&#xff0c;喜欢的人很优秀&#xff0c;周围人的嘲笑&#xff0c;以及&#xff0c;天生傲骨。 漏洞描述 利用漏洞&#xff0c;攻击者可以读取 Windows 或 Linux 服务器上的任…

【QT开发-Pyside】使用Pycharm与conda配置Pyside环境并新建工程

知识拓展 Pycharm 是一个由 JetBrains 开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它主要用于 Python 编程语言的开发。Pycharm 提供了代码编辑、调试、版本控制、测试等多种功能&#xff0c;以提高 Python 开发者的效率。 Pycharm 与 Python 的关系 Pycharm 是…

微信小程序教程:如何在个人中心实现头像贴纸功能

在微信小程序中&#xff0c;个性化设置是提升用户体验的重要手段。本文将详细介绍如何在个人中心模块中实现头像贴纸功能&#xff0c;让用户可以自由地装饰自己的头像。 头像贴纸功能允许用户在个人头像上添加装饰性贴纸&#xff0c;增加个性化表达。以下是实现该功能的主要步骤…

安全帽佩戴识别摄像机:守护安全的智能之眼

在现代工业和建筑等诸多领域中&#xff0c;安全始终是重中之重。每一处施工现场、每一个生产车间都潜藏着可能对人员造成伤害的风险因素。而安全帽&#xff0c;作为保护工作人员头部免受伤害的关键装备&#xff0c;其是否被正确佩戴就显得尤为关键。此时&#xff0c;安全帽佩戴…

mysql数据库--索引

索引 1.索引 在数据中索引最核心的作用就是&#xff1a;加速查找 1.1 索引原理 索引的底层是基于BTree的数据存储结构 如图所示&#xff1a; 很明显&#xff0c;如果有了索引结构的查询效率比表中逐行查询的速度要快很多且数据越大越明显。 数据库的索引是基于上述BTree的…

硬件(驱动开发概念)

驱动程序开发 裸机驱动&#xff08;无操作系统&#xff09; Linux驱动 以计算机技术为基础&#xff0c;在软件和硬件层间可以被剪裁的专业硬件计算机系统 SOC&#xff1a;片上系统 Kernel&#xff1a;内核 x86 &#xff08;CISC:complex instruction set computer 复杂指令…

一款前后端分离CRM客户关系管理系统,支持客户,商机,线索,合同,发票,审核,商品等功能(附源码)

前言 在当今竞争激烈的商业环境中&#xff0c;企业面临着各种挑战&#xff0c;其中包括如何更有效地管理和跟进潜在客户以提高销售业绩。传统的客户管理方式往往效率低下&#xff0c;无法实时更新客户-信息&#xff0c;导致销售机会流失。因此&#xff0c;市场上急需一款能够简…

GitHub 上高星 AI 开源项目推荐

FIFO-Diffusion 介绍&#xff1a;FIFO-Diffusion 是一个创新的开源项目&#xff0c;它能够基于文本描述生成无限长度的高品质视频&#xff0c;而无需任何预先的模型训练。这一技术的核心在于其高效的内存管理策略和先进的扩散模型&#xff0c;使得即使是小型GPU配置也能轻松应…

ES学习笔记

目录 简介 原理 基础概念 lucene总结 es的进步 实现过程 写入流程 搜索过程 和Mysql搭配 学习来源&#xff1a;https://i12pc3nf6d.feishu.cn/wiki/FnPwwGXGli1ANGkaMz5chvhmn2e#share-OYKJdYhehotnMgxrBiUcZSJJnCb https://i12pc3nf6d.feishu.cn/wiki/FnPwwGXGli1ANG…

【Linux】【Hadoop】大数据基础实验一

实验一&#xff1a;熟悉常用的Linux操作和Hadoop操作 一、实验目的 Hadoop运行在Linux系统上&#xff0c;因此&#xff0c;需要学习实践一些常用的Linux命令。本实验旨在熟悉常用的Linux操作和Hadoop操作&#xff0c;为顺利开展后续其他实验奠定基础。 二、实验平台 操作系统…

comp 9517 Computer Vision week2

图像处理 1.空间域操作(Spatial domain operation)1.1 点(Point operation)1.2 邻域(Neighbourhood operation)空间滤波(spatial filtering)修复边界问题(fixing the border problem)通过卷积进行空间滤波(Spatial filtering by convolution)卷积特性&#xff1a;滤波器强度梯度…

Java 缓存机制与缓存失效

在分布式系统中&#xff0c;缓存 是提高系统性能、减轻数据库压力的常用技术。合理的缓存策略不仅能提升响应速度&#xff0c;还能节省资源。不过&#xff0c;缓存并不是万能的&#xff0c;缓存失效 是开发中必须考虑的问题。如果处理不好&#xff0c;可能会导致数据不一致或性…

使用库函数点亮一个LED灯

软件设计 STM32Gpio的介绍 如果想让LED0点亮&#xff0c;那么R12就要是高电平&#xff0c;LED0就要是低电平&#xff0c;也就是PF9就是低电平 F407系统主频要工作在168MHZ F103的话是工作在72mhz F429的话就180MHZ 接着我们就要使能Gpio的时钟&#xff0c;使能之后对GPIO相关…