C++编译器优化技术:RVO、NRVO和复制省略
现代编译器缺省会使用RVO(return value optimization,返回值优化)、NRVO(named return value optimization、命名返回值优化)和复制省略(Copy elision)技术,来减少拷贝次数来提升代码的运行效率
注1:vc6、vs没有提供编译选项来关闭该优化,无论是debug还是release都会进行RVO和复制省略优化
注2:vc6、vs2005以下及vs2005+ Debug上不支持NRVO优化,vs2005+ Release支持NRVO优化
注3:g++支持这三种优化,并且可通过编译选项:-fno-elide-constructors来关闭优化
RVO
#include <stdio.h>
class A
{
public:
A()
{
printf("%p construct\n", this);
}
A(const A& cp)
{
printf("%p copy construct\n", this);
}
~A()
{
printf("%p destruct\n", this);
}
}; A GetA()
{
return A();
} int main()
{
{
A a = GetA();
} return ;
}
在g++和vc6、vs中,上述代码仅仅只会调用一次构造函数和析构函数 ,输出结果如下:
0x7ffe9d1edd0f construct
0x7ffe9d1edd0f destruct
在g++中,加上-fno-elide-constructors选项关闭优化后,输出结果如下:
0x7ffc46947d4f construct // 在函数GetA中,调用无参构造函数A()构造出一个临时变量temp
0x7ffc46947d7f copy construct // 函数GetA return语句处,把临时变量temp做为参数传入并调用拷贝构造函数A(const A& cp)将返回值ret构造出来
0x7ffc46947d4f destruct // 函数GetA执行完return语句后,临时变量temp生命周期结束,调用其析构函数~A()
0x7ffc46947d7e copy construct // 函数GetA调用结束,返回上层main函数后,把返回值变量ret做为参数传入并调用拷贝构造函数A(const A& cp)将变量A a构造出来
0x7ffc46947d7f destruct // A a = GetA()语句结束后,返回值ret生命周期结束,调用其析构函数~A()
0x7ffc46947d7e destruct // A a要离开作用域,生命周期结束,调用其析构函数~A()
注:临时变量temp、返回值ret均为匿名变量
下面用c++代码模拟一下其优化行为:
#include <new>
A& GetA(void* p)
{
//由于p的内存是从外部传入的,函数返回后仍然有效,因此返回值可为A&
//vs中,以下代码还可以写成:
// A& o = *((A*)p);
// o.A::A();
// return o;
return *new (p) A(); // placement new
} int main()
{
{
char buf[sizeof(A)];
A& a = GetA(buf);
a.~A();
} return ;
}
NRVO
g++编译器、vs2005+ Release(开启/O2及以上优化开关)
修改上述代码,将GetA的实现修改成:
A GetA()
{
A o;
return o;
}
在g++、vs2005+ Release中,上述代码也仅仅只会调用一次构造函数和析构函数 ,输出结果如下:
0x7ffe9d1edd0f construct
0x7ffe9d1edd0f destruct
g++加上-fno-elide-constructors选项关闭优化后,和上述结果一样
0x7ffc46947d4f construct
0x7ffc46947d7f copy construct
0x7ffc46947d4f destruct
0x7ffc46947d7e copy construct
0x7ffc46947d7f destruct
0x7ffc46947d7e destruct
但在vc6、vs2005以下、vs2005+ Debug中,没有进行NRVO优化,输出结果为:
18fec4 construct // 在函数GetA中,调用无参构造函数A()构造出一个临时变量o
18ff44 copy construct // 函数GetA return语句处,把临时变量o做为参数传入并调用拷贝构造函数A(const A& cp)将返回值ret构造出来
18fec4 destruct // 函数GetA执行完return语句后,临时变量o生命周期结束,调用其析构函数~A()
18ff44 destruct // A a要离开作用域,生命周期结束,调用其析构函数~A()
下面用c++代码模拟一下vc6、vs2005以下、vs2005+ Debug上的行为:
#include <new>
A& GetA(void* p)
{
A o;
//由于p的内存是从外部传入的,函数返回后仍然有效,因此返回值可为A&
//vs中,以下代码还可以写成:
// A& t = *((A*)p);
// t.A::A(o);
// return t;
return *new (p) A(o); // placement new
} int main()
{
{
char buf[sizeof(A)];
A& a = GetA(buf);
a.~A();
} return ;
}
注:与g++、vs2005+ Release相比,vc6、vs2005以下、vs2005+ Debug只优化掉了返回值到变量a的拷贝,命名局部变量o没有被优化掉,所以最后一共有2次构造和析构的调用
复制省略
典型情况是:调用构造函数进行值类型传参
void Func(A a)
{
} int main()
{
{
Func(A());
} return ;
}
在g++和vc6、vs中,上述代码仅仅只会调用一次构造函数和析构函数 ,输出结果如下:
0x7ffeb5148d0f construct
0x7ffeb5148d0f destruct
在g++中,加上-fno-elide-constructors选项关闭优化后,输出结果如下:
0x7ffc53c141ef construct // 在main函数中,调用无参构造函数构造实参变量o
0x7ffc53c141ee copy construct // 调用Func函数后,将实参变量o做为参数传入并调用拷贝构造函数A(const A& cp)将形参变量a构造出来
0x7ffc53c141ee destruct // 函数Func执行完后,形参变量a生命周期结束,调用其析构函数~A()
0x7ffc53c141ef destruct // 返回main函数后,实参变量o要离开作用域,生命周期结束,调用其析构函数~A()
下面用c++代码模拟一下其优化行为:
void Func(const A& a)
{
} int main()
{
{
Func(A());
} return ;
}
优化失效的情况
开启g++优化,得到以下各种失效情况的输出结果:
(1)根据不同的条件分支,返回不同变量
A GetA(bool bflag)
{
A a1, a2;
if (bflag)
return a1;
return a2;
} int main()
{
A a = GetA(true); return ;
}
0x7ffc3cca324f construct
0x7ffc3cca324e construct
0x7ffc3cca327f copy construct
0x7ffc3cca324e destruct
0x7ffc3cca324f destruct
0x7ffc3cca327f destruct
注1:2次缺省构造函数调用:用于构造a1、a2
注2:1次拷贝构造函数调用:用于拷贝构造返回值
注3:这儿仍然用右值引用优化掉了一次拷贝函数调用:返回值赋值给a
(2)返回参数变量
(3)返回全局变量
(4)返回复合数据类型中的成员变量
(5)返回值赋值给已构造好的变量(此时会调用operator==赋值运算符)
参考
What are copy elision and return value optimization?
Named Return Value Optimization in Visual C++ 2005
C++编译器优化技术:RVO、NRVO和复制省略的更多相关文章
- 返回值优化(RVO)
C++的函数中,如果返回值是一个对象,那么理论上它不可避免的会调用对象的构造函数和析构函数,从而导致一定的效率损耗.如下函数所示: A test() { A a; return a; } 在test函 ...
- 翻译「C++ Rvalue References Explained」C++右值引用详解 Part6:Move语义和编译器优化
本文为第六部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...
- 【M20】协助完成“返回值优化(RVO)”
1.方法返回对象,会导致临时对象的产生,这降低了效率,const Rational operator* (const Rational& lhs,Rational& rhs).有没有什 ...
- java编译期优化与执行期优化技术浅析
java语言的"编译期"是一段不确定的过程.由于它可能指的是前端编译器把java文件转变成class字节码文件的过程,也可能指的是虚拟机后端执行期间编译器(JIT)把字节码转变成机 ...
- 【深入理解JAVA虚拟机】第4部分.程序编译与代码优化.2.运行期优化。这章提到的具体的优化技术,应该对以后做性能工作会有帮助。
1.概述 Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”(Hot Spot Code). 为了提高 ...
- 《深入理解java虚拟机》学习笔记之编译优化技术
郑重声明:本片博客是学习<深入理解Java虚拟机>一书所记录的笔记,内容基本为书中知识. Java程序员有一个共识,以编译方式执行本地代码比解释方式更快,之所以有这样的共识,除去虚拟机解释 ...
- JDK and JRE File Structure JAVA_HOME HotSpot优化技术
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jdkfiles.html Java Platform, Standard ...
- java编译器优化和运行期优化
概述 最近在看jvm优化,总结一下学习的相关知识 (一)javac编译器 编译过程 1.解析与填充符号表过程 1).词法.语法分析 词法分析将源代码的字符流转变为标记集合,单个字符是程序编 ...
- node.js背后的引擎V8及优化技术
本文将挖掘V8引擎在其它方面的代码优化,如何写出高性能的代码,及V8的性能诊断工具.V8是chrome背后的javascript引擎,因此本文的相关优化经验也适用于基于chrome浏览器的javasc ...
随机推荐
- python学习-price
"""登录功能:用户名和密码存在{'name':'huahua','pwd':'123456'}字典中,通过控制台输入用户名和密码判读是否正确,然后给出对应的提示消息:登 ...
- Rabbit安装(单机及集群,阿里云)
Rabbit安装(单机及集群,阿里云) 前言 虽然我并不是部署人员,但是自己私人测试环境的各类东东还是得自己安装的. 尤其在规模不大的公司,基本安装部署工作都是后端的份内之事. 那么最令人痛苦的,莫过 ...
- 真伪随机数 ——Random和SecureRandom
Random Random用来创建伪随机数.所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的. 要生成一个随机数,可以使用nextInt().nextLong().nextFlo ...
- 如何在PHP框架里把Traits使用起来
我们都知道PHP只能使用单一继承,这意味着一个类只能从另一个类继承. 例如,您可能想从几个不同的类继承方法以防止代码重复. PHP 5.4中添加了新的语言特性Traits,而且它在Laravel框架 ...
- Typroa 常用快捷键
Typora 常用快捷键 文件操作 Ctrl + N :新建文件 Ctrl + shift + N :新建窗口 Ctrl + O :打开 Ctrl + P : 快速打开(快速打开之前编辑过的历史文件) ...
- Mbp,一个用于学习.net core的开发框架
Mbp(https://github.com/mbpframework/Mbp)是一个.net core 3的企业级web开发框架,是我个人用于学习.net core而发起的一个开源项目.这个借鉴了国 ...
- Android 自定义吐司通知
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...
- Builder模式的目的是解耦构建过程,为什么要用内部类?
还没有看过Builder模式的作用,看过一篇介绍Builder模式的文章,这里是关于Builder模式的思考:思考是否有比新建一个内部类更好的方法,首先想到的是 package xyz.n490808 ...
- Appium+Java 自动化测试系列一:环境搭建
Appium+Java 自动化测试框架搭建主要分为以下几个方面的下载安装及环境配置 1.Java开发环境 涉及到的内容又jdk.编译器工具(推荐jdk 1.8.Eclipse编译器或者IDEA编译工具 ...
- Hive 性能测试工具 hive-testbench
下载: yum -y install gcc gcc-c++ maven 下载地址Github:https://github.com/hortonworks/hive-testbench/git cl ...