C++实践1:RVO优化
一.问题引入
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优化相关推荐
- 【C++ 语言】面向对象 ( 函数重载 | 运算符重载 | 运算符重载两种定义方式 | 拷贝构造方法 | RVO 优化 | NRVO 优化 )
文章目录 函数重载 运算符重载 ( 类内部定义云算符重载 ) 运算符重载 ( 类外部定义运算符重载 ) 可重载的运算符 拷贝构造方法 编译器优化 ( RVO 优化 | NRVO 优化 ) 完整代码示例 ...
- 让互联网更快的协议,QUIC在腾讯的实践及性能优化
本文来自腾讯资深研发工程师罗成在InfoQ的技术分享. 本文首发InfoQ公众号,系腾讯技术工程事业群与InfoQ合作的"腾讯技术工程"专栏第二篇文章,新的一年,我们将会为技术人员 ...
- 一致性协议raft详解(四):raft在工程实践中的优化
一致性协议raft详解(四):raft在工程实践中的优化 前言 性能优化 client对raft集群的读写 参考链接 前言 有关一致性协议的资料网上有很多,当然错误也有很多.笔者在学习的过程中走了不少 ...
- nginx php7提速,nginx+php7-fpm 性能提升几倍跟踪实践结果并优化
nginx+php7-fpm 性能提升几倍跟踪实践结果并优化 nginx+php7-fpm 性能提升几倍,跟踪实践结果并优化 历史ubuntu服务器使用的apache+php5,现在使用nginux+ ...
- 数字逻辑综合工具实践-DC-07 ——综合优化(二)和RTL coding 和DFT
数字逻辑综合工具实践-DC-07 --综合优化(二)和RTL coding 和DFT 主要内容: 1. Pipeline优化 2. RTL设计时的一些注意事项 3. DFT简介 (DFT是后端里很重要 ...
- oCPC实践录 | 成本优化策略之CVR门槛(1)
北京秋天的周末,刚下过一场小雨,外面凉飕飕的.我宅在家里,吃着脆甜的冬枣,剥着三红柚子,正想着要不要写一下文章. 突然电话响起,老板打电话过来说运营要测试一下广告的落地页,需要下调CVR门槛.原本以为 ...
- oCPC实践录 | 成本优化策略之CVR门槛(2)
在上篇文章oCPC实践录 | 成本优化策略之CVR门槛(1)中,设计CVR门槛由广告主控制的成本优化产品,通过这个产品,广告主可以根据自己的实际需求,调整CVR门槛,获取自己想要的那部分流量,媒体方仅 ...
- 记一次接口性能优化实践总结:优化接口性能的八个建议
前言 最近对外接口偶现504超时问题,原因是代码执行时间过长,超过nginx配置的15秒,然后真枪实弹搞了一次接口性能优化.在这里结合优化过程,总结了接口优化的八个要点,希望对大家有帮助呀~ 数据量比 ...
- 实践App内存优化:如何有序地做内存分析与优化
由于项目里之前线上版本出现过一定比例的OOM,虽然比例并不大,但是还是暴露了一定的问题,所以打算对我们App分为几个步骤进行内存分析和优化,当然内存的优化是个长期的过程,不是一两个版本的事,每个版本都 ...
最新文章
- 处理错误:ORA-27101: shared memory realm does not exist 解决方案
- 霸王洗发水经理被指冲击报社殴打记者
- 平时优化SQL的集合
- 张雪峰计算机科学与技术学什么,张雪峰看好的三大专业是什么 前景好的专业...
- 算法 --- 记一道面试dp算法题
- 安装redis出现cc adlist.o /bin/sh:1:cc:not found
- dubbo注册中心介绍
- Python内置数据结构——字符串string
- iOS、OSX恶意软件风险大增 果粉稍不留神即遭“黑手”
- 慕课软件质量保证与测试(第六章.课后作业)
- 关于DoIP 协议的理解
- Icon图标格式(用于生成*.ico图标)
- 机器码反编译c语言,如何把任意一段机器码或unicode码反汇编成汇编指令
- 列表(list)使用方法详解
- 1.6 电源树中电流的计算方法(硬件基础系列)
- 企业微信公众号运营技巧有哪些
- 解决双硬盘下一个windows两个linux操作系统的grub引导问题
- 十字路口通行优先权,十字路口通行规则图解
- lsdyna如何设置set中的node_list_如何画出一幅好看的图
- C# 获取适配器网络连接IP地址,子网掩码,DNS,数据包等信息