一.问题引入

1. 如下代码会输出什么?

class String{public:explicit String(const char* p){size_t size = std::strlen(p) + 1;data = new char[size];std::memcpy(data,p,size);cout<<"1"<<endl;}~String(){delete[] data;}String(const String& that){size_t size = strlen(that.data) + 1;data = new char[size];std::memcpy(data,that.data,size);cout<<"2"<<endl;}
private:char* data;
};int main(){auto temp = String(String("hi"));return 0;
}

2.答案

3. 代码解读,问题提出

  • 定义了两个String构造函数,一个使用const char*进行初始化,另一个使用String变量进行拷贝初始化
  • 主函数里,我们用const char*“hi”初始化了一个临时String变量, 再用这个临时String变量初始化另一个String变量
  • 如果是按照上述思路执行的话,应该是输出1和2和2,但是最后只输出了1,说明,没有执行临时量copy的过程,问题出在哪了?编译器优化?

二.借助汇编分析问题

1. 命令

g++ -o main.s -S main.cpp

2.内容如下

  • const char* 构造函数
  • main函数

3.汇编代码解读

  • 保存寄存器入栈

  • 开辟24字节的栈空间,

  • 其中24字节用于存储金丝雀值(不知道金丝雀的可以去百度)

  • 随后8字节,存储的是temp类,记住,类成员函数不占空间,我们的类A,sizeof(A) == 8


4. 汇编层面解释调用成员函数

多说一句,类的成员函数如何被调用

  • 其实成员函数存储在.text节中,
  • 我们调用成员函数时,先在栈/堆上分配sizeof(类)的空间(设其地址为A),空类大小为1(而不是0),
  • 此时这个空间的地址(地址A),就代表了this指针,
  • 我们将这个A(或称为this指针),传递到.text节中的某个成员函数,
  • 成员函数隐式的第一个参数就为this,所以成员函数可以区分是哪个类在构造对象或调用对象,
  • 成员函数随后在this(A地址)上进行各种操作,就是对A这块地址操作,就是对我们分配出的类实例在操作
  • 不同的类实例有不同的this,即有不同的地址空间,所以我们可以使用一个成员函数操纵所有的类

5. 本函数调用的构造函数

可以看出,是const char*,而随后并没有再调用其他的构造函数了。
为什么没有调用拷贝构造函数?
原来是编译器帮我们做了优化!!!

三.问题解答:RVO优化

1. RVO优化是什么

  • 返回值优化,return value optimization, 这是一种编译器优化机制,当函数返回一个对象的时候,如果自己创造一个临时对象进行返回(对应于main函数里,我们的String("hi")),那么这个临时对象会消耗一个构造函数的调用(String(const char*)),一个复制构造函数的调用(String(const String& s)),以及一个析构函数的调用(析构掉临时值)

  • 经过返回值优化,就可以将成本降低到一个构造函数的代价。这样就省去了一次拷贝构造函数的调用和依次析构函数的调用。

  • 注意从C++17开始,RVO优化不再是可选的,而是默认的

2. 关闭RVO优化

-fno-elide-constructors选项可以取消编译器的 copy-elision 优化策略

3. NRVO优化是什么

  • (Named Return Value Optimization)。具名返回值优化(NRVO),是对于按值返回“具名对象”(就是有名字的变量)时的优化手段,其实道理是一样的,但由于返回的值是具名变量,情况会复杂很多。所以,能执行优化的条件更苛刻。

4. 结合本例谈RVO优化底层如何实现

  • 其实从上面我们对于汇编代码的讲解就已经提到了
  • 我们直接从temp的地址进行构造,而不是先构造出一个临时变量,再把该变量的地址传给temp的拷贝构造函数,
  • 编译器采取的是直接把“hi”的地址传给temp
  • 编译器足够智能!!!

四. 验证结果

1. 关掉RVO优化

  • 输出了1,2,2
  • 第一个2:临时变量传入拷贝构造函数,作为拷贝构造函数的参数
  • 第二个2:构造完成,赋值给temp,调用拷贝构造函数

2. 查看底层汇编

  • main函数的汇编语句
  • 自己去尝试实现,读个两遍,再来看下面解释
  • 可以看出,关闭优化后,拷贝构造函数也被加入了.text中,命名为_ZN6StringC1ERKS_
  • 调用顺序也是符合预期
  • 说明我们最开始的问题得到了验证。
  • 如有错误,欢迎指正。

C++实践1:RVO优化相关推荐

  1. 【C++ 语言】面向对象 ( 函数重载 | 运算符重载 | 运算符重载两种定义方式 | 拷贝构造方法 | RVO 优化 | NRVO 优化 )

    文章目录 函数重载 运算符重载 ( 类内部定义云算符重载 ) 运算符重载 ( 类外部定义运算符重载 ) 可重载的运算符 拷贝构造方法 编译器优化 ( RVO 优化 | NRVO 优化 ) 完整代码示例 ...

  2. 让互联网更快的协议,QUIC在腾讯的实践及性能优化

    本文来自腾讯资深研发工程师罗成在InfoQ的技术分享. 本文首发InfoQ公众号,系腾讯技术工程事业群与InfoQ合作的"腾讯技术工程"专栏第二篇文章,新的一年,我们将会为技术人员 ...

  3. 一致性协议raft详解(四):raft在工程实践中的优化

    一致性协议raft详解(四):raft在工程实践中的优化 前言 性能优化 client对raft集群的读写 参考链接 前言 有关一致性协议的资料网上有很多,当然错误也有很多.笔者在学习的过程中走了不少 ...

  4. nginx php7提速,nginx+php7-fpm 性能提升几倍跟踪实践结果并优化

    nginx+php7-fpm 性能提升几倍跟踪实践结果并优化 nginx+php7-fpm 性能提升几倍,跟踪实践结果并优化 历史ubuntu服务器使用的apache+php5,现在使用nginux+ ...

  5. 数字逻辑综合工具实践-DC-07 ——综合优化(二)和RTL coding 和DFT

    数字逻辑综合工具实践-DC-07 --综合优化(二)和RTL coding 和DFT 主要内容: 1. Pipeline优化 2. RTL设计时的一些注意事项 3. DFT简介 (DFT是后端里很重要 ...

  6. oCPC实践录 | 成本优化策略之CVR门槛(1)

    北京秋天的周末,刚下过一场小雨,外面凉飕飕的.我宅在家里,吃着脆甜的冬枣,剥着三红柚子,正想着要不要写一下文章. 突然电话响起,老板打电话过来说运营要测试一下广告的落地页,需要下调CVR门槛.原本以为 ...

  7. oCPC实践录 | 成本优化策略之CVR门槛(2)

    在上篇文章oCPC实践录 | 成本优化策略之CVR门槛(1)中,设计CVR门槛由广告主控制的成本优化产品,通过这个产品,广告主可以根据自己的实际需求,调整CVR门槛,获取自己想要的那部分流量,媒体方仅 ...

  8. 记一次接口性能优化实践总结:优化接口性能的八个建议

    前言 最近对外接口偶现504超时问题,原因是代码执行时间过长,超过nginx配置的15秒,然后真枪实弹搞了一次接口性能优化.在这里结合优化过程,总结了接口优化的八个要点,希望对大家有帮助呀~ 数据量比 ...

  9. 实践App内存优化:如何有序地做内存分析与优化

    由于项目里之前线上版本出现过一定比例的OOM,虽然比例并不大,但是还是暴露了一定的问题,所以打算对我们App分为几个步骤进行内存分析和优化,当然内存的优化是个长期的过程,不是一两个版本的事,每个版本都 ...

最新文章

  1. 处理错误:ORA-27101: shared memory realm does not exist 解决方案
  2. 霸王洗发水经理被指冲击报社殴打记者
  3. 平时优化SQL的集合
  4. 张雪峰计算机科学与技术学什么,张雪峰看好的三大专业是什么 前景好的专业...
  5. 算法 --- 记一道面试dp算法题
  6. 安装redis出现cc adlist.o /bin/sh:1:cc:not found
  7. dubbo注册中心介绍
  8. Python内置数据结构——字符串string
  9. iOS、OSX恶意软件风险大增 果粉稍不留神即遭“黑手”
  10. 慕课软件质量保证与测试(第六章.课后作业)
  11. 关于DoIP 协议的理解
  12. Icon图标格式(用于生成*.ico图标)
  13. 机器码反编译c语言,如何把任意一段机器码或unicode码反汇编成汇编指令
  14. 列表(list)使用方法详解
  15. 1.6 电源树中电流的计算方法(硬件基础系列)
  16. 企业微信公众号运营技巧有哪些
  17. 解决双硬盘下一个windows两个linux操作系统的grub引导问题
  18. 十字路口通行优先权,十字路口通行规则图解
  19. lsdyna如何设置set中的node_list_如何画出一幅好看的图
  20. C# 获取适配器网络连接IP地址,子网掩码,DNS,数据包等信息

热门文章

  1. 社群运营中粉丝对于商家的价值是什么?
  2. 今天给大家介绍一个起名神器“苹果手机的随机取名功能”
  3. 学习C#从俄罗斯方块开始(二)俄罗斯方块的规则和算法的简单实现
  4. 买东西被坑了?python采集数据详情,不在害怕~
  5. 163/126/QQ邮箱服务器地址以及SSL端口
  6. 2017年暑期实习求职经历
  7. 单片机知识:了解PWM调光
  8. 关于Qt Creator载入项目卡在reading project
  9. Python 本身真的有用吗?
  10. echarts的x轴标签重叠 解决