聊聊 C++ 右值引用 和 移动构造函数

聊聊 C++ 右值引用 和 移动构造函数

一: 背景

最近在看 C++ 的右值引用和移动构造函数,感觉这东西一时半会还挺难理解的,可能是没踩过这方面的坑,所以没有那么大的深有体会,不管怎么说,这一篇我试着聊一下。

二: 右值引用

1. 它到底解决了什么问题?

在其他编程语言中,很少听到 右值引用 这个词,我个人感觉还是 C++ 这个 值类型 优先的语言基因决定的,我们都知道 值类型 作为方法参数或者返回值时会生成自身的副本,如果 值类型 很大,那一来一回生成若干个深复制的 临时对象 将会产生巨大的性能开销。

总结一句话:右值引用 就是尽可能的减少这中间 临时对象 个数,尤其是关联到 heap 上的对象,仅此而已。

2. 右值引用是个什么样子?

说到 右值引用 得先说什么是 右值,左值 , 左值 一般都是带有内存地址的变量,而 右值 一般是立即数或者运算过程中的临时对象,这种对象不会有地址值,是不是很绕,我举个例子吧。

int main(){int i = 10;int j = 11;int sum = i + j;}

  • 10,11,(i+j)
  • 属于右值,因为它本身没有内存地址,除非把它们放入到栈中或者堆中。

  • i,j,sum
  • 属于左值,因为它们是线程栈上地址的标识符。

    知道了 左右值 概念,接下来理解 左右值引用 就很简单了,既然是 引用,必然是多个变量指向同一个地址,对吧,修改下代码如下:

    int main(){int i = 10;int& k = i;//左值引用int&& m = 10;//右值引用}

    接下来看下汇编代码:

    33: int i = 10;00FB182F mov dword ptr [ebp-0Ch],0Ah 34: int& k = i;00FB182F mov dword ptr [ebp-0Ch],0Ah 00FB1836 lea eax,[ebp-0Ch] 00FB1839 mov dword ptr [ebp-18h],eax 36: int&& m = 10;00FB183C mov dword ptr [ebp-30h],0Ah 00FB1843 lea eax,[ebp-30h] 00FB1846 mov dword ptr [ebp-24h],eax

    从汇编代码看,它们是一模一样的,也就是说在汇编层面,其实并没有 右值引用 和 左值引用 一说。

    有了这些基础,我们来看下更复杂的 class 结构。

    三: 右值引用如何减少对象的创建

    1. 简要思路

    其实仔细想一想,减少临时对象的创建,无非就是在运算过程中复用一些对象,不需要每次都走赋值构造函数来进行深复制,画个图就像下面这样。

    明白了这个思路,接下来我们举一个例子说明。

    2. 一个简单的例子

    C++ 最烦的地方就是有太多的构造函数, 数不胜数,太尴尬了,这里我做一个简单的 + 操作例子。

    #include #include using namespace std;class StringBuidler {public:char* str;int length;public:StringBuidler() {}StringBuidler(int len, char c) {this->str = new char[len];this->str[0] = c;this->length = len;}StringBuidler(const StringBuidler& s) {printf(“StringBuidler:深复制 “);this->length = s.length;this->str = new char[s.length];for (size_t i = 0; i str[i] = s.str[i];}}StringBuidler operator+(const StringBuidler& p) {StringBuidler tmp;tmp.length = this->length + p.length;tmp.str = new char[tmp.length];int index = 0;for (size_t i = 0; i length; i++){tmp.str[index++] = this->str[i];}for (size_t i = 0; i < p.length; i++){tmp.str[index++] = p.str[i];}return tmp;}};int main(){StringBuidler s1(10, 'a');StringBuidler s2(5, 'b');StringBuidler s3 = s1 + s2;printf("s3.length=%d, s1.length=%d, s2.length=%d ", s3.length, s1.length, s2.length);}折叠

    从这个例子中可以看到,s1+s2 操作中出现了一次 深copy,具体代码出现在 return 处,汇编代码如下:

    因为是深复制,所以会再次生成一个 new char[] ,如果 new char[] 很大,那将会是不必要的性能开销,能不能像我画的图一样,将 s3 中的 str 指针直接指向 tmp 所持有的 heap 上的 char[] 数组来达到复用目的呢? 肯定是可以的。

    3. 性能优化方案

    这里需要用 右值引用 + 移动构造函数 让 s3.str 指向 tmp.str,从而避免复制构造函数,在 StringBuilder 类中加一个方法如下:

    StringBuidler(StringBuidler&& s) {this->str = s.str;this->length = s.length;s.str = nullptr;}

    然后把程序跑起来,截图如下:

    可以看到,深复制已经没有了,这个过程会在 return 处被调用,编译器会判断如果是右值的话,自动走 移动构造函数,没有这个函数就会走 赋值构造函数。

    四: 总结

    总之 右值引用 可以让你尽可能的复用一些中间对象,达到一个性能上的提升,其实对 C# 程序员来说,这么简单的引用赋值,C++ 搞出了这么多概念,真的很难理解,可能还是那句话,这是 C++ 的值类型优先的基因决定的。

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    用户投稿
    上一篇 2022年7月26日 15:14
    下一篇 2022年7月26日 15:14

    相关推荐

    • 存储过程语法(sql server存储过程语法)

      今天小编给各位分享存储过程语法的知识,其中也会对sql server存储过程语法进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧! oracle存储过程基本语法…

      2022年11月26日
    • 广州花都岭南批发地女装在哪拿货好(广州花都岭南批发地女装)

      广州的服装批发市场人气一直也都挺高的,不过很多商家第一次来广州进货,对于一些女装货源批发还不是很了解。广州花都岭南批发地女装在哪拿货好?现在广州服装货源批发哪里最便宜呢?今天小编整…

      2022年11月23日
    • 拼多多免费领商品有什么规则(拼多多免费领商品金币后面是什么)

      拼多多免费领商品活动相信不少小伙伴都参加过,吸引力还是很大的,只要砍价成功就可以免费领到商品,一些小伙伴第一次参加不知道拼多多免费领商品有什么规则?下面小编为大家带来拼多多免费领商…

      2022年11月21日
    • 马斯克凌晨一点半晒“代码审查”现场,编排他的段子比疯狂星期四还多

      梦晨 Pine 发自 凹非寺 量子位 | 公众号 QbitAI 每一个真正会写代码的人,请在下午2点到总部10层报到。 每一个真正会写代码的人,请在下午2点到总部10层报到。 马斯…

      2022年11月21日
    • 京东店铺类型有哪些京东入驻有什么资质要求

      今天的互联网发展迅速,让传统企业有了更多选择,但也同样也对刚触网的商家增添了许多迷茫,近日知舟电商就收到很多商家朋友询问京东入驻相关问题,今天知舟君就给大家分享下。 一.京东入驻准…

      2022年11月18日
    • 为什么店铺定位搜不到(如何将公司位置弄在微信定位上)

      随着互联网的发展,越来越多的应用出现在我们面前,这让人们的生活更加的便捷。我们大家对于微信都很是熟悉,这个软件拥有着数以亿计的用户资源,微信的各种功能也是非常的实用,让人们的用户体…

      2022年11月18日
    • 科研十年磨一剑 我国科学家成功克隆野生玉米高蛋白基因

      央视网消息:经过10年不懈努力,中国科学院分子植物科学卓越创新中心和上海师范大学科研团队合作,首次从野生玉米中成功克隆出高蛋白基因,并通过杂交实验,有效提高了现代玉米的蛋白含量,这…

      2022年11月17日
    • 怎么删除自己的追评(淘宝追评可以删除吗)

      一、淘宝店铺每个评价类型的处理方案都是不同的,那具体哪些评价类型该如何区分呢? 1、主评为好评时:不支持修改或者删除评价的,若中评/差评改为好评,也不可修改或删除 ; 2、当主评为…

      2022年11月17日
    • 分享qq群做排名的3个技巧(qq群如何做排名)

      做QQ群,感觉大家最头疼的应该还是引流问题吧。除了常见的论坛引流,群友裂变之外,每天通过Q群搜索进来的流量也是挺可观的,毕竟这种免费流量咱们也不能浪费不是?这边引出第一个问题,就是…

      2022年11月17日
    • gfsoso(gfsoso是什么)

      eSCIHUB搜索引擎强大无比,只要有网就能下载你要的文献,无需购买数据库。 说到查资料大家最先想到的是各类搜索引擎提供的数据库,当然百度学术在一定程度上也能完成一些论文的查阅工作…

      2022年11月16日

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息