第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.mzph.cn/diannao/54500.shtml

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

相关文章

引领长期投资新篇章:价值增长与财务安全的双重保障

随着全球金融市场的不断演变&#xff0c;长期投资策略因其稳健性和对价值增长的显著推动作用而日益受到投资者的重视。在这一背景下&#xff0c;Zeal Digital Shares&#xff08;ZDS&#xff09;项目以其创新的数字股票产品&#xff0c;为全球投资者提供了一个全新的长期投资平…

最优化理论与自动驾驶(十一):基于iLQR的自动驾驶轨迹跟踪算法(c++和python版本)

最优化理论与自动驾驶&#xff08;四&#xff09;&#xff1a;iLQR原理、公式及代码演示 之前的章节我们介绍过&#xff0c;iLQR&#xff08;迭代线性二次调节器&#xff09;是一种用于求解非线性系统最优控制最优控制最优控制和规划问题的算法。本章节介绍采用iLQR算法对设定…

分析redis实现分布式锁的思路

文章目录 1、基于redis实现分布式锁&#xff1a;利用key的唯一性1.1、独占排他1.2、死锁问题1.2.1、redis客户端程序获取了锁之后&#xff0c;服务器立马宕机&#xff0c;就会导致死锁。1.2.2、不可重入&#xff1a;可重入 1.3、原子性&#xff1a;加锁和过期之间&#xff1a;s…

深入剖析Docker容器安全:挑战与应对策略

随着容器技术的广泛应用&#xff0c;Docker已成为现代应用开发和部署的核心工具。它通过轻量级虚拟化技术实现应用的隔离与封装&#xff0c;提高了资源利用率。然而&#xff0c;随着Docker的流行&#xff0c;其安全问题也成为关注焦点。容器化技术虽然提供了良好的资源隔离&…

4.C_数据结构_队列

概述 什么是队列&#xff1a; 队列是限定在两端进行插入操作和删除操作的线性表。具有先入先出(FIFO)的特点 相关名词&#xff1a; 队尾&#xff1a;写入数据的一段队头&#xff1a;读取数据的一段空队&#xff1a;队列中没有数据&#xff0c;队头指针 队尾指针满队&#…

FPGA与Matlab图像处理之直方图均衡化

文章目录 一、什么是直方图?二、什么是直方图均衡化&#xff1f;三、Matlab实现直方图均衡化的步骤第一步&#xff1a; 彩色图像转成灰度图像第二步&#xff1a;提取亮度通道的直方图第三步&#xff1a;累计亮度通道的像素值频率第四步&#xff1a; 映射到新的灰度值 四、Veri…

嵌入式 开发技巧和经验分享

文章目录 前言嵌入式 开发技巧和经验分享目录1.1嵌入式 系统的 定义1.2 嵌入式 操作系统的介绍1.3 嵌入式 开发环境1.4 编译工具链和优化1.5 嵌入式系统软件开发1.6 嵌入式SDK开发2.1选择移植的系统-FreeRtos2.2FreeRtos 移植步骤2.3 系统移植之中断处理2.4系统移植之内存管理2…

【java面经】Redis速记

目录 基本概念 string hash list set zset 常见问题及解决 缓存穿透 缓存击穿 缓存雪崩 Redis内存管理策略 noeviction allkeys-lru allkeys-random volatile-random volatile-ttl Redis持久化机制 RDB快照 AOF追加文件 Redis多线程特性 Redis应用场景 缓…

【医学半监督】置信度指导遮蔽学习的半监督医学图像分割

摘要: 半监督学习(Semi-supervised learning)旨在利用少数标记数据和多数未标记数据训练出高性能模型。现有方法大多采用预测任务机制,在一致性或伪标签的约束下获得精确的分割图,但该机制通常无法克服确认偏差。针对这一问题,本文提出了一种用于半监督医学图像分割的新…

【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的?

【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的&#xff1f; 【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的&#xff1f; 文章目录 【梯度下降|链式法则】卷积神经网络中的参数是如何传输和更新的&#xff1f;1. 什么是梯度&#xff1f;2.梯度…

2024-04-23 人工智能增强天基通信和传感

砺道智库2024-04-23 11:18 北京 据国家防务网4月19日报道&#xff0c;随着商业卫星、军事星座及其所有数据在太空中流动的数量不断增加&#xff0c;政府和行业运营商表示&#xff0c;他们正在寻求人工智能来帮助他们处理日益复杂的任务。 人工智能软件使用户能够在轨道上改变航…

饲料颗粒机全套设备有哪些机器组成

饲料颗粒机全套设备通常包括原料粉碎、混合机、制粒机、冷却器、筛分机、包装机以及配套的电气控制等多个部分组成&#xff1a;1、粉碎机&#xff1a;将各种饲料原料进行清理、去杂、破碎等预处理&#xff0c;确保原料的纯净度和适宜粒度&#xff0c;为后续加工做准备。2、混合…

【永磁同步电机(PMSM)】 5. PMSM 的仿真模型

【永磁同步电机&#xff08;PMSM&#xff09;】 5. PMSM 的仿真模型 1. 基于 Simulink 的仿真模型1.1 PMSM 的数学模型1.2 Simulink 仿真模型1.3 模块封装&#xff08;mask&#xff09;1.4 三相PMSM矢量控制仿真模型 2. Simscape 的 PMSM 模块2.1 PMSM 模块的配置2.2 PMSM 模块…

数据结构与算法学习day22-回溯算法-分割回文串、复原IP地址、子集

一、分割回文串 1.题目 131. 分割回文串 - 力扣&#xff08;LeetCode&#xff09; 2.思路 分割回文串可以抽象为一棵树形结构。 递归用来纵向遍历&#xff0c;for循环用来横向遍历&#xff0c;切割线&#xff08;就是图中的红线&#xff09;切割到字符串的结尾位置&#xf…

WIFI路由器的套杆天线简谈

❝本次推文简单介绍下WIFI路由器的套杆天线。 路由器天线 路由器在这个万物互联的时代&#xff0c;想必大家对其都不陌生。随着科技的发展&#xff0c;常用的路由器上的天线也越来越多&#xff0c;那么问题来了&#xff1a;天线越多&#xff0c;信号越好吗&#xff1f;路由器…

浅谈Spring Cloud:认识微服务

SpringCloud就是分布式微服务架构的一站式解决方案&#xff0c;是微服务架构落地的多种技术的集合。 目录 微服务远程调用 Eureka注册中心 搭建Eureka Server 注册组件 服务拉取 当各种各样的服务越来越多&#xff0c;拆分的也越来越细&#xff0c;此时就会出现一个服务集…

计算机毕业设计 社区医疗服务系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

MySQL高阶1919-兴趣相同的朋友

题目 请写一段SQL查询获取到兴趣相同的朋友。用户 x 和 用户 y 是兴趣相同的朋友&#xff0c;需满足下述条件&#xff1a; 用户 x 和 y 是朋友&#xff0c;并且用户 x and y 在同一天内听过相同的歌曲&#xff0c;且数量大于等于三首. 结果表 无需排序 。注意&#xff1a;返…

常见排序(C语言版)

1.排序的概念及其应用 1.1排序的概念 排序&#xff1a;​ 在计算机科学与数学中&#xff0c;一个排序算法&#xff08;英语&#xff1a;Sorting algorithm&#xff09;是一种能将一串资料依照特定排序方式排列的算法。 稳定性&#xff1a;假定在待排序的记录序列中&#xff…

聚观早报 | 小米三折叠手机专利曝光;李斌谈合肥投资蔚来

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 9月20日消息 小米三折叠手机专利曝光 李斌谈合肥投资蔚来 索尼PS5 Pro包装亮相 新一代Spectacles AR眼镜发布 通…