c++积累8-右值引用、移动语义

news2024/9/20 14:30:36

1、右值引用

1.1 背景

c++98中的引用很常见,就是给变量取个别名,具体可以参考c++积累7
在c++11中,增加了右值引用的概念,所以c++98中的引用都称为左值引用

1.2 定义

右值引用就是给右值取个名字,右值有了名字之后就成了普通变量,可以像使用左值一样使用。

语法:数据类型&& 变量名=右值

示例:

#include <iostream>

class AA {
public:
    int m_a = 9;
};

AA getTemp() {
    return AA();
}

int main() {
    using namespace std;

    int &&a = 3; // 3是右值,给它起个名字叫a
    int b = 8; // b 是左值, 8是右值
    int &&c = b + 5; // b+5是右值,给它取个名字叫c

    AA &&aa = getTemp();// getTemp()返回值是右值(临时变量),给它起个名字叫aa

    cout << "a= " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
    cout << "aa.m_a= " << aa.m_a << endl;

    return 0;
}

在这里插入图片描述

1.3 常量左值引用

常量左值引用是一个万能的引用类型,它可以绑定非常量左值、常量做值、右值,在绑定右值的时候,常量左值引用可以像右值引用一样将右值的生命期延长,缺点是只能读不能改

    int a = 1;
    const int &ra = a; // a是非常量左值
    const int b = 2;
    const int &rb = b; // b是常量左值
    const int &rc = 1; // 1是右值

2、移动语义

2.1 背景

如果一个对象中有堆区资源,需要编写拷贝构造函数和赋值函数,实现深拷贝。
深拷贝把对象中堆区资源复制了一份,如果资源(被拷贝的资源)是临时对象,拷贝完就没有什么意义了,这样会造成没有意义的资源申请和释放操作。
如果能够直接使用对象拥有的资源,可以节省资源申请和释放的时间。c++11增加的移动语义就能够做到这一点。

2.2 定义

移动语义增加两个构造函数:移动构造函数 、 移动赋值函数
移动构造函数语法:
类名(类名&& 源对象){…}
移动赋值函数语法:
类名& operator=(类名&& 源对象){…}

demo:

#include <iostream>
#include <string.h>

using namespace std;

class AA {
public:
    int *m_data = nullptr; //数据成员,指向堆区资源的指针
    AA() = default; // 启用默认构造函数

    void alloc() {  // 给数据成员m_data分配内存
        m_data = new int;  // 分配内存
        memset(m_data, 0, sizeof(int)); //初始化已分配的内存
    }

    AA(const AA &a) {  //拷贝构造函数 - 拷贝语义
        cout << "调用了拷贝构造函数 。\n";  // 显示自己被调用的日志
        if (m_data == nullptr) alloc(); // 如果没有分配内存,就分配
        memcpy(m_data, a.m_data, sizeof(int)); //把数据从源对象中拷贝过来
    }

    AA(AA &&a) {  //拷贝构造函数 - 移动语义
        cout << "调用了移动语义拷贝构造函数 。\n";  // 显示自己被调用的日志
        if (m_data != nullptr) delete m_data; // 如果已经分配内存,先释放
        m_data = a.m_data; // 把资源从源对象中转移过来
        a.m_data = nullptr; // 把源对象中的指针置空
    }

    AA &operator=(const AA &a) { //赋值函数 - 拷贝语义
        cout << "调用了赋值函数。\n"; // 显示自己被调用的日志
        if (this == &a) return *this; // 避免自我赋值
        if (m_data == nullptr) alloc(); // 如果没有分配内存,就分配
        memcpy(m_data, a.m_data, sizeof(int)); // 把数据从源对象中拷贝过来
        return *this;
    }

    AA &operator=(AA &&a) { //赋值函数 - 移动语义
        cout << "调用了移动语义赋值函数。\n"; // 显示自己被调用的日志
        if (this == &a) return *this; // 避免自我赋值
        if (m_data != nullptr) delete m_data; // 如果已经分配内存,先释放
        m_data = a.m_data; // 把资源从源对象中转移过来
        a.m_data = nullptr; // 把源对象中的指针置空
        return *this;
    }

    ~AA() { // 析构函数
        cout << "调用析构函数" << endl;
        if (m_data != nullptr) {
            delete m_data;
            m_data == nullptr;
        }
    }

};

int main() {
    AA a1; // 创建对象a1
    a1.alloc(); // 分配堆区资源
    *a1.m_data = 3; // 给堆区内存赋值
    cout << "*a1.m_data = " << *a1.m_data << ",addr = " << a1.m_data << endl;

    AA a2 = a1; // 调用拷贝构造函数 - 这个地方a1是左值就调用拷贝语义构造函数,如果是右值,则调用移动语义构造函数
    cout << "*a2.m_data = " << *a2.m_data << ",addr = " << a2.m_data << endl;

    AA a3;
    a3 = a1; // 调用赋值函数
    cout << "*a3.m_data = " << *a3.m_data << ",addr = " << a3.m_data << endl;

    auto f = [] { // 返回AA类对象的lambda函数
        AA aa;
        aa.alloc();
        *aa.m_data = 10;
        return aa;
    };
    AA a4 = f(); // lambda函数返回临时对象,是右值,将调用移动构造函数
    cout << "*a4.m_data = " << *a4.m_data << ",addr = " << a4.m_data << endl;

    AA a6;
    a6 = f(); // lambda函数返回临时对象,是右值,将调用移动赋值函数
    cout << "*a6.m_data = " << *a6.m_data << ",addr = " << a6.m_data << endl;

    return 0;
}

在这里插入图片描述

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

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

相关文章

【达摩院OpenVI】基于流感知的视频目标检测网络LongShortNet

论文&代码 论文链接&#xff1a;[arxiv]代码&应用&#xff1a; 开源代码&#xff1a;[github code]开源应用&#xff1a;[modelscope] 背景介绍 传统视频目标检测&#xff08;Video Object Detection, VOD&#xff09;任务以一段视频作为输入&#xff0c;利用视频的…

项目上线|慕尚集团携手盖雅工场,用数字化推动人效持续提升

过去十年&#xff0c;中国零售业以前所未有的速度被颠覆、被重塑&#xff0c;数字化则是其中重要的推动要素。 随着数字化转型的深入&#xff0c;零售企业的数字化不再局限于布局线上渠道&#xff0c;且更关乎其背后企业核心运营能力的全链路数字化改造。而贯穿于运营全链路的…

mybatis缓存的详细理解和使用

mybatis缓存的简单理解和使用 mybatis缓存数据的介绍 缓存是存在于内存中的临时数据&#xff0c;使用缓存的目的是减少和数据库的数据进行交互的次数&#xff0c;提高执行效率。像很多持久化框架一样&#xff0c;Mybatis也提供了缓存策略&#xff0c;通过缓存策略来减少数据库…

RflySim平台使用篇 | Coptersim系列教程(三)

# 导读 # CopterSim作为RflySim平台核心仿真软件&#xff0c;其主要实现两部分功能&#xff1a;模型和通信&#xff0c;掌握CopterSim使用方法即可轻松运行多旋翼运动动态模型&#xff0c;并连同其他软件构成软/硬件在环仿真。本篇教程将详细介绍coptersim仿真log数据获取。 Co…

webpack plugin源码解析(六) CompressionWebpackPlugin

文章目录 作用涉及 webpack API处理 asset 钩子compilation.hooks.processAssets返回或新建缓存&#xff1a;compilation.getCache返回 asset 文件信息&#xff1a;compilation.getAsset文件名匹配函数&#xff1a;compiler.webpack.ModuleFilenameHelpers.matchObject模版字符…

科研热点|8本期刊被剔除SCIE,4月最新SCIE/SSCI目录已更新 (附下载)~

2023年4月18日&#xff0c;科睿唯安更新了Web of Science核心期刊目录&#xff0c;此次更新后SCIE期刊目录共包含9505本期刊&#xff0c;SSCI期刊目录共包含3557本期刊。此次4月SCIE & SSCI期刊目录更新&#xff0c;与3月更新相比 (警惕&#xff01;多达50本SCI/SSCI被剔除…

Kafka中时间轮分析与Java实现

仿kafka实现java版时间轮_java实现时间轮算法_Hekliu的博客-CSDN博客 https://www.cnblogs.com/softlin/p/7426083.html https://blog.csdn.net/happyjacob/article/details/128518700 一、背景 在Kafka中应用了大量的延迟操作但在Kafka中 并没用使用JDK自带的Timer或是Dela…

m3u8转mp4下载,有URL,IV

1、背景 在线m3u8现在是主流加密方式的视频。 2、下载m3u8视频难点 首先需要连接m3u8文件格式,这个自行百度,其次加密方式确定和key以及iv。如果没有加密直接找一个在线的m3u8转mp4就可以,但是问题就是很多带加密,而且key不是m3m8中key URL返回的数据,市面上软件无法直…

基于matlab评估机场监控雷达上 5G 新无线电 (NR) 信号的干扰

一、前言 随着5G NR系统的频率范围超出LTE中使用的频段&#xff0c;频谱管理变得更加复杂。对扩大5G覆盖范围的需求是由更高的数据速率和更低的延迟的好处推动的。新5G基站的实施反过来又推动了了解这些信号如何影响在相同频段上运行的已安装系统的需求。其中一个系统是空中交通…

类对象

一、类初识 类&#xff1a;表示一种事物所具有的共同特征和行为 对象&#xff1a;一个类的实例 如下图&#xff0c;通过狗这个类进行详解 这是一个Dog类 对象&#xff1a;斗牛犬、小猎犬、牧羊犬 类中的属性&#xff1a;breed(品种)、size(大小)、color(颜色)、age(年龄)、 …

OpenCv基础之绘图及几何变换实例

文章目录 OpenCv基础之绘图及几何变换实例创建背景图线段绘制矩形绘制圆绘制椭圆绘制绘制多边形添加文字 几何变换图像平移图像缩放图像旋转仿射变换透视变化 OpenCv基础之绘图及几何变换实例 绘图在图像处理中&#xff0c;主要是在处理完图像后&#xff0c;将图像中的目标进行…

Python算法设计 - 哈夫曼编码

目录 一、哈夫曼树二、哈夫曼编码三、Python算法实现四、作者Info 一、哈夫曼树 上图是根据“this is an example of a huffman tree”中得到的字母频率来建构的哈夫曼树 二、哈夫曼编码 多年来&#xff0c;哈夫曼编码在统计数据压缩方面是非常先进的&#xff0c;应当指出&am…

C# 类库打包推送到nuget

步骤1&#xff1a;注册nuget 账号&#xff0c;可以使用outlook邮箱进行注册 步骤2&#xff1a;建立 apikey 名字自己起&#xff0c;Glob Pattern 填入“*” 步骤3&#xff1a;把程序打包&#xff0c;打包很简单右键vs2022 打包就好 但是注意*.csproj 文件修改,修改目的是为了…

IGS 产品长文件命名方式简介

文章目录 Part.I IntroductionPart.II 文件命名方式Chap.I 官方说明Chap.II 实例 Reference Part.I Introduction 2022 年 11 月 30 日&#xff08;DOY 331, GPSWD 22380&#xff09;及以后&#xff0c;IGS 的参考框架从 IGS-14 切换为 用 IGS-20&#xff0c;最新的卫星和地…

vue3中<script setup> 和 setup函数的区别

<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。相比于普通的 <script> 语法&#xff0c;它具有更多优势&#xff1a; 更少的样板内容&#xff0c;更简洁的代码。能够使用纯 TypeScript…

拿下模板进阶

模板进阶 1. 非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将…

代码随想录训练营day53|1143、最长公共子序列;1035、不相交的线;53、最大子序和动态规划

1143、最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长公共子序列的长度。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08;也可以不删除任何字符&#xff…

如何在一个中文大模型上,加入招投标字段标注的数据,搭建一个招投标字段解析的Transformer模型?

ChatGPT方案1 在一个中文大模型上加入招投标字段标注的数据&#xff0c;并搭建招投标字段解析的Transformer模型可以通过以下步骤实现&#xff1a; 收集并标注招投标相关的数据。可以使用现有的数据集&#xff0c;也可以通过爬虫技术获取相关数据&#xff0c;然后进行人工标注。…

Linux应用编程(进程)

一、进程与程序 注册进程终止处理函数 atexit() #include <stdlib.h> int atexit(void (*function)(void));使用该函数需要包含头文件<stdlib.h>。 函数参数和返回值含义如下&#xff1a; function&#xff1a;函数指针&#xff0c;指向注册的函数&#xff0c;此…

使用S3协议通过dfs实现Spring的SPI机制和spring.factories

目录 参考一、SPI机制1、什么是SPI2、使用场景&#xff1f;3、使用介绍4、代码演示新建工程edevp-dfs-api的spi接口新建阿里云oss实现类新建minio实现类新建测试工程edevp-demo测试 5、总结优点&#xff1a;解耦缺点&#xff1a; 二、Spring Boot的扩展机制之Spring Factories1…