为什么会有右值引用?(移动构造、移动赋值)

news2024/9/23 9:36:22

         目录

1、左值引用的缺陷

2、移动构造:解决临时对象的深拷贝

3、拓展:移动赋值 


1、左值引用的缺陷

左值引用作为函数参数传递,减少了参数拷贝;但是作为函数返回值,并不适用于所有场景,比如要返回一个临时对象。

直接返回临时对象的话,此时编译器就会调用拷贝构造,构造一个新的临时对象保存到main函数的栈上,然后销毁原本的临时对象。如果对象中有一个大小为10000的数组,深拷贝对程序运行效率影响较大

class Point
{
public:
    Point(int x, int y): _x(x), _y(y) {}
    Point(const Point& p):_x(p._x), _y(p._y)
    {
        cout << "Point(Point& p)被调用了 —— 深拷贝" << endl;
    }

    Point& operator=(const Point& p)
    {
        _x = p._x;
        _y = p._y;
    }

    Point getPos() {
        Point p(_x, _y);        // 创建临时对象
        return p;               // 返回临时对象
    }
private:
    int _x;
    int _y;
};

2、移动构造:解决临时对象的深拷贝

移动构造是右值引用的应用之一,其本质就是将要返回的临时对象的资源移动到其他地方。下面通过示意图和案例来了解。

(1) 移动构造的本质

移动构造也是构造函数的一种,区别在于,传递的参数必须是右值,即表达式、函数返回值等。其本质是将右值保存的资源,转移到其他临时对象。以上述 getPos 函数为例

getPos函数返回一个临时对象A,临时对象A出了作用域就被销毁,肯定不能直接返回,所以会先调用移动构造(函数返回值是右值)。

移动构造会将临时对象A的资源转移到新构造的对象B中,然后再销毁临时对象A,这样的话,就减少了深拷贝,提升程序的运行效率。

 

(2) 移动构造具体实现

所谓转移资源,其实就是将临时对象A和临时对象B的资源交换:

  • 临时对象A:传递的右值形参 p
  • 临时对象B:构造的对象 *this
// 移动构造
Point(Point&& p)
{
    // cout << "Point(Point&& p) 被调用了 —— 资源转移" << endl;
    this->swap(p);
}

// 资源交换
void swap(Point& p)
{
    std::swap(_x, p._x);
    std::swap(_y, p._y);
}

(3) 移动构造测试

我们在先前的代码中加入移动构造,然后使用同样的方法测试

class Point
{
public:
    Point(int x, int y): _x(x), _y(y) {}
    Point(const Point& p):_x(p._x), _y(p._y)
    {
        cout << "Point(Point& p)被调用了 —— 深拷贝" << endl;
    }

    Point& operator=(const Point& p)
    {
        _x = p._x;
        _y = p._y;
    }

    // 移动构造
    Point(Point&& p)
    {
        cout << "Point(Point&& p) 被调用了 —— 资源转移" << endl;
        swap(*this, p);
    }
    
    // 交换资源
    void swap(Point& p)
    {
        std::swap(_x, p._x);
        std::swap(_y, p._y);
    }
    Point getPos() {
        Point p(_x, _y);
        return p;
    }
private:
    int _x;
    int _y;
};

 

3、拓展:移动赋值 

(1) 起因

当我们把一个对象赋给另一个对象的时候,其实就是把一个对象里的内容完全拷贝到另一个对象,这个时候也会发生深拷贝。

Point p(10, 20);
// Point p1 = p;        // 会被编译器优化成调用拷贝构造
Point p1(20, 30);
p1 = p;        // 赋值完毕以后打算舍弃 p
    

假如我们的目的是,将 p 赋给 p1 以后舍弃对象p,若对象p中包含一个大小为10000的数组,这个时候的深拷贝就比较影响效率了。

(2) 移动赋值

移动赋值借用了移动构造的思路,既然不需要对象p,那就索性将一个对象p的资源转移到对象p1

那么我们就需要新增一个 operator=() 的重载了

Point& operator=(Point&& p)
{
    // cout << "Point& operator=(Point&& p) 被调用了 —— 移动赋值,资源转移" << endl;
    this->swap(p);    // swap 函数的定义详见上面的移动构造
    return *this;
}

 

(3) 移动赋值测试

测试用的代码需要稍微改动一下,移动赋值的形参必须是一个右值,这里我们需要用move函数将对象p 转换成右值。其内部也是以特殊的方式直接返回传入的对象,这样的话返回值就变成了一个临时对象,也就是右值。

int main() {
    Point p(10, 20);
    Point p1(20, 30);
    p1 = move(p);

    return 0;
}

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

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

相关文章

Linux——innode

目录 回顾缓冲区 标准错误流的理解 文件系统 Inode VS 文件名 创建/删除/查看文件系统做了什么 软硬链接 动静态库 习题 回顾缓冲区 关掉1&#xff0c;log.txt中没文件是因为&#xff0c;字符串在缓冲区当中&#xff0c;缓冲区还没刷新&#xff0c;我们把fd给关了…

堆的实现及应用

下面用C语言介绍堆的实现以及应用 文章目录1. 堆的简介2. 堆的实现HeapInitHeapDestroyHeapPushHeapPop3. 堆的应用堆排序TopK问题1. 堆的简介 堆是一颗完全二叉树。这里所说的堆是一种非连续的数据结构&#xff0c;与操作系统内存分布的堆是两回事&#xff0c;它们没有任何联…

金融帝国实验室(Capitalism Lab)官方中文汉化包下载(v4.03)

<FCT汉化小组>Vol.001号作品 ————————————— ◎作品名称&#xff1a;金融帝国实验室&#xff08;CapLab&#xff09;官方汉化包 ◎汉化作者&#xff1a;FCT汉化小组&#xff08;Enlight Software认证&#xff09; ◎发布版本&#xff1a;CapLab Simplifi…

POJ 1845 Sumdiv题解(C++ 整数惟一分解定理+分治法求等比数列之和+快速幂)

文章目录整数惟一分解定理分治法求等比数列和完整代码传送门&#xff1a; POJ 1845 SumDiv 整数惟一分解定理 任何一个大于1的整数n都可以分解成若干个质因数&#xff08;素因数&#xff09;的连乘积&#xff0c;如果不计各个素因数的顺序&#xff0c;那么这种分解是唯一的&a…

王者荣耀入门技能树

前言 最近在学习技能树&#xff0c;我也试着写一写技能树&#xff0c;放松一下。 这里附上一张可爱的兔兔应景。仔细看&#xff0c;后边题目会提到&#xff0c;哈哈。 职业 以下哪个不属于王者荣耀中的职业&#xff1a; 射手法师辅助亚瑟 技能 以下哪个技能可以加快打野…

春节假期后,如何快速让员工恢复上班的元气和状态?

每当假期过后&#xff0c;总有一些员工无法快速恢复工作状态&#xff0c;团队的氛围也很难一下子热起来。而春节假期既是长假&#xff0c;又是过节氛围最浓厚的假期&#xff0c;节后返工的涣散问题自然更明显一些。但对于服装店铺来说&#xff0c;年后开工正处于旺季&#xff0…

【Vue】我的尚品汇项目笔记---20230109~20230120

014之前可参考官方笔记 https://blog.csdn.net/weixin_43424325/article/details/121684101 015-axios二次封装 api/index.js 设定 //当前模块&#xff0c;API进行统一管理&#xff0c;即对请求接口统一管理 import requests from "/api/request";//首页三级分类…

通达信插件获取并存储通达信商品指数的实时数据

一、引子 通达信商品指数一共有23个&#xff0c;如下图所示&#xff1a; 如果想获取历史数据&#xff0c;只需要通过通达信的数据下载和导出功能即可&#xff0c;现在我们需要获取这23个指数的实时数据&#xff0c;通过导出功能就没有办法了。 在最初的阶段&#xff0c;考虑的…

微服务自动化管理【IDEA使用Docker插件进行一键部署】

本章目标 IDEA使用Docker插件实现springboot项目的一键部署 要开两个虚拟机 server registry server上进行操作 Docker开启远程api端口(注意这种配置方式只适用于开发和学习&#xff0c;在公共网络中不要这样配置&#xff0c;容易引发安全问题) 默认情况下dokcer是不支持远程…

linux基本功系列之find命令实战

文章目录前言&#x1f680;&#x1f680;&#x1f680;一. find命令介绍二. find常用参数及语法格式三. 示范案例3.1 查找符合文件名规则的文件3.2 根据文件类型类查找文件3.3 按照更改时间或访问时间等查找文件3.4 查找并执行相应的命令3.5 按照文件大小来查找3.6 按照文件所有…

启动hive报错no hbase in

启动hive报错no hbase in 将hdfs和yarn都启动成功之后&#xff0c;启动hive&#xff0c;如下所示&#xff1a;[atguiguhadoop102 conf]$ cd /opt/module/hive/ [atguiguhadoop102 hive]$ bin/hive报错信息如下which: no hbase in (/usr/local/bin:/usr/bin:/usr/local/sbin:/us…

C++ · 类和对象 · 02 | 类的6个默认成员函数

啊我摔倒了..有没有人扶我起来学习.... &#x1f471;个人主页&#xff1a;《CGod的个人主页》\color{Darkorange}{《CGod的个人主页》}《CGod的个人主页》交个朋友叭~ &#x1f492;个人社区&#xff1a;《编程成神技术交流社区》\color{Darkorange}{《编程成神技术交流社区》…

【操作系统】—— 如何安装双系统与多系统(带你快速了解)

&#x1f4dc; “作者 久绊A” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴。 &#x1f341; 操作系统【带你快速了解】对于电脑来说&#xff0c;如果说…

博客系统项目的自动化测试

作者&#xff1a;~小明学编程 文章专栏&#xff1a;测试开发 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 博客界面 测试用例 界面测试 功能测试 性能测试 兼容性测试 易用性测试 安全性测试 ​编辑自动化测试 登录界面的测试 界面文字模块 测…

ubuntu使用教程与常用命令

ubuntu使用教程 一、 Ubuntu简介 Ubuntu&#xff08;乌班图&#xff09;是一个基于Debian的以桌面应用为主的Linux操作系统&#xff0c;据说其名称来自非洲南部祖鲁语或科萨语的“ubuntu”一词&#xff0c;意思是“人性”、“我的存在是因为大家的存在”&#xff0c;是非洲传…

Python爬虫之Scrapy框架系列(5)——项目实战【某瓣Top250电影所有信息的txt文本存储】

上篇文章已经成功解析提取到豆瓣Top250电影想要的所有数据。下一步就是将其交给管道进行存储。 目录&#xff1a;1. 编写items.py文件&#xff08;定义结构化数据字段&#xff09;2. 爬虫文件里将数据一一对应字段名&#xff1a;3. 将数据返回给管道&#xff1a;4. 编写pipelin…

MCAL系列介绍04-ICU

本文框架1. 前言2. 基本概念3. ICU采集过程3.1 获取周期占空比3.2 获取边沿数量3.3 获取时间戳4. Autosar系列文章快速链接1. 前言 ICU驱动器是使用Input Capture Uint模块&#xff08;ICU&#xff09;解调PWM信号、计数脉冲、测量频率和占空比、生成简单中断以及唤醒中断的模…

树莓派配置Python虚拟环境、安装PyQt5、安装PySide2

要从头设置好一台可用于开发的树莓派&#xff0c;可以参考树莓派 4B 无屏幕&#xff0c;连接WiFi、SSH、VNC&#xff0c;系统换源、pip换源&#xff0c;安装中文输入法 Python虚拟环境 树莓派&#xff08;或者说arm平台&#xff09;使用Python虚拟环境的正确方式是使用pipenv…

【手写 Vue2.x 源码】第三十九篇 - 组件部分 - 创建组件虚拟节点

一&#xff0c;前言 上篇&#xff0c;介绍了组件部分-组件的合并&#xff0c;主要涉及以下几个点&#xff1a; 组件初始化情况&#xff1b;组件合并的位置&#xff1b;组件合并的策略&#xff1b;组件合并后测试&#xff1b; 本篇&#xff0c;组件部分-组件的编译&#xff1…

【C语言】对<进阶版三子棋>的完善和改进

这篇文章主要是对前面三子棋游戏的完善和改进。 文章目录 目录 1.将棋子*和#&#xff0c;改为1和0&#xff1b; 2.电脑下棋显示坐标 3.可以选择电脑先手或玩家先手 4.在退出游戏时显示游戏信息 5.完善后的游戏效果 二、完整程序代码 1.game.h 2.test.c 3.game.c 总结 前言 h…